Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71ebb36fe9 | ||
|
|
78a0b86327 | ||
|
|
2636c16a97 | ||
|
|
fd77c0242d | ||
|
|
e74819a900 | ||
|
|
9b7f696c9b | ||
|
|
0230d614e7 | ||
|
|
252d99ad78 | ||
|
|
1ffc200350 | ||
|
|
807d89b2b2 | ||
|
|
4013afa1f1 | ||
|
|
a580927ceb | ||
|
|
bf2cf52034 | ||
|
|
81bb8b7c31 | ||
|
|
a825007fb5 | ||
|
|
988124d96a | ||
|
|
f0de815296 | ||
|
|
0e2d58c887 | ||
|
|
b155382626 | ||
|
|
f362d740af |
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.16</Version>
|
||||
<Version>3.0.0.20</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Authors>Diego</Authors>
|
||||
|
||||
@@ -116,16 +116,16 @@
|
||||
|
||||
|
||||
<ItemGroup >
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.DLT645" Version="*" />
|
||||
<!--<PackageReference Include="ThingsGateway.Foundation.Adapter.DLT645" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.Modbus" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.OPCDA" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.OPCUA" Version="*" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.Siemens" Version="*" />
|
||||
<!--<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" />
|
||||
<PackageReference Include="ThingsGateway.Foundation.Adapter.Siemens" Version="*" />-->
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.DLT645\ThingsGateway.Foundation.Adapter.DLT645.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Modbus\ThingsGateway.Foundation.Adapter.Modbus.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.OPCDA\ThingsGateway.Foundation.Adapter.OPCDA.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.OPCUA\ThingsGateway.Foundation.Adapter.OPCUA.csproj" />
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" />-->
|
||||
<ProjectReference Include="..\..\Foundation\ThingsGateway.Foundation.Adapter.Siemens\ThingsGateway.Foundation.Adapter.Siemens.csproj" />
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup >
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.16</Version>
|
||||
<Version>3.0.0.20</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||
|
||||
@@ -409,13 +409,9 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase
|
||||
|
||||
private void Init(ModbusAddress mAddress)
|
||||
{
|
||||
if (ModbusServer01ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer01ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer02ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer02ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer03ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer03ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer04ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer04ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,13 +429,9 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase
|
||||
|
||||
private void Init(ModbusAddress mAddress)
|
||||
{
|
||||
if (ModbusServer01ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer01ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer02ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer02ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer03ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer03ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
if (ModbusServer04ByteBlocks.TryAdd(mAddress.Station, new(1024 * 128)))
|
||||
ModbusServer04ByteBlocks[mAddress.Station].SetLength(1024 * 128);
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(1024 * 128));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#region copyright
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
@@ -8,6 +9,7 @@
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endregion
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -17,22 +19,23 @@ using Opc.Ua.Client;
|
||||
using Opc.Ua.Client.ComplexTypes;
|
||||
using Opc.Ua.Configuration;
|
||||
|
||||
|
||||
//修改自https://github.com/dathlin/OpcUaHelper 与OPC基金会net库
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.OPCUA;
|
||||
|
||||
/// <summary>
|
||||
/// 订阅委托
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public delegate void DataChangedEventHandler((VariableNode variableNode, DataValue dataValue, JToken jToken) value);
|
||||
|
||||
/// <summary>
|
||||
/// OPCUAClient
|
||||
/// </summary>
|
||||
public class OPCUAClient : IDisposable
|
||||
{
|
||||
|
||||
#region 属性,变量等
|
||||
|
||||
/// <summary>
|
||||
/// 当前配置
|
||||
/// </summary>
|
||||
@@ -48,30 +51,35 @@ public class OPCUAClient : IDisposable
|
||||
/// </summary>
|
||||
public List<string> Variables = new();
|
||||
|
||||
private readonly Action<byte, object, string, Exception> _logAction;
|
||||
|
||||
/// <summary>
|
||||
/// 当前的变量名称/OPC变量节点
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, VariableNode> _variableDicts = new();
|
||||
|
||||
private readonly object checkLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前的订阅组,组名称/组
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, Subscription> dic_subscriptions = new();
|
||||
|
||||
private readonly ApplicationInstance m_application = new();
|
||||
|
||||
private readonly ApplicationConfiguration m_configuration;
|
||||
private SessionReconnectHandler m_reConnectHandler;
|
||||
private EventHandler m_ReconnectComplete;
|
||||
private EventHandler m_ReconnectStarting;
|
||||
private EventHandler<KeepAliveEventArgs> m_KeepAliveComplete;
|
||||
private EventHandler<bool> m_ConnectComplete;
|
||||
private EventHandler<OpcUaStatusEventArgs> m_OpcStatusChange;
|
||||
|
||||
private ISession m_session;
|
||||
|
||||
/// <summary>
|
||||
/// 默认的构造函数,实例化一个新的OPC UA类
|
||||
/// </summary>
|
||||
public OPCUAClient(Action<byte, object, string, Exception> log)
|
||||
public OPCUAClient()
|
||||
{
|
||||
_logAction = log;
|
||||
var certificateValidator = new CertificateValidator();
|
||||
certificateValidator.CertificateValidation += CertificateValidation;
|
||||
|
||||
@@ -90,7 +98,6 @@ public class OPCUAClient : IDisposable
|
||||
MaxMessageQueueSize = 1000000,
|
||||
MaxNotificationQueueSize = 1000000,
|
||||
MaxPublishRequestCount = 10000000,
|
||||
|
||||
},
|
||||
|
||||
SecurityConfiguration = new SecurityConfiguration
|
||||
@@ -133,8 +140,6 @@ public class OPCUAClient : IDisposable
|
||||
StoreType = CertificateStoreType.Directory,
|
||||
StorePath = AppContext.BaseDirectory + @"OPCUAClientCertificate\pki\trustedUser",
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
TransportQuotas = new TransportQuotas
|
||||
@@ -160,8 +165,6 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
m_configuration.Validate(ApplicationType.Client);
|
||||
m_application.ApplicationConfiguration = m_configuration;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -188,6 +191,52 @@ public class OPCUAClient : IDisposable
|
||||
/// SessionReconnectHandler
|
||||
/// </summary>
|
||||
public SessionReconnectHandler ReConnectHandler => m_reConnectHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a good keep alive from the server arrives.
|
||||
/// </summary>
|
||||
public event EventHandler<KeepAliveEventArgs> KeepAliveComplete
|
||||
{
|
||||
add { m_KeepAliveComplete += value; }
|
||||
remove { m_KeepAliveComplete -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a reconnect operation starts.
|
||||
/// </summary>
|
||||
public event EventHandler ReconnectStarting
|
||||
{
|
||||
add { m_ReconnectStarting += value; }
|
||||
remove { m_ReconnectStarting -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a reconnect operation completes.
|
||||
/// </summary>
|
||||
public event EventHandler ReconnectComplete
|
||||
{
|
||||
add { m_ReconnectComplete += value; }
|
||||
remove { m_ReconnectComplete -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised after successfully connecting to or disconnecing from a server.
|
||||
/// </summary>
|
||||
public event EventHandler<bool> ConnectComplete
|
||||
{
|
||||
add { m_ConnectComplete += value; }
|
||||
remove { m_ConnectComplete -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised after the client status change
|
||||
/// </summary>
|
||||
public event EventHandler<OpcUaStatusEventArgs> OpcStatusChange
|
||||
{
|
||||
add { m_OpcStatusChange += value; }
|
||||
remove { m_OpcStatusChange -= value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前活动会话。
|
||||
/// </summary>
|
||||
@@ -231,7 +280,7 @@ public class OPCUAClient : IDisposable
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"初始化{items[i]}变量订阅失败", ex);
|
||||
UpdateStatus(3, DateTime.Now, $"初始化{items[i]}变量订阅失败,错误原因:{ex}");
|
||||
}
|
||||
}
|
||||
m_subscription.AddItems(monitoredItems);
|
||||
@@ -247,9 +296,9 @@ public class OPCUAClient : IDisposable
|
||||
var isError = m_subscription.MonitoredItems.Any(a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode));
|
||||
if (isError)
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"创建以下变量订阅失败:{Environment.NewLine}{m_subscription.MonitoredItems.Where(
|
||||
UpdateStatus(3, DateTime.Now, $"创建以下变量订阅失败:{Environment.NewLine}{m_subscription.MonitoredItems.Where(
|
||||
a => a.Status.Error != null && StatusCode.IsBad(a.Status.Error.StatusCode))
|
||||
.Select(a => $"{a.StartNodeId.ToString()}:{a.Status.Error.ToString()}").ToJsonString()}", null);
|
||||
.Select(a => $"{a.StartNodeId.ToString()}:{a.Status.Error.ToString()}").ToJsonString()}");
|
||||
}
|
||||
|
||||
lock (dic_subscriptions)
|
||||
@@ -281,7 +330,6 @@ public class OPCUAClient : IDisposable
|
||||
item.Value.Delete(true);
|
||||
m_session.RemoveSubscription(item.Value);
|
||||
try { item.Value.Dispose(); } catch { }
|
||||
|
||||
}
|
||||
dic_subscriptions.Clear();
|
||||
}
|
||||
@@ -304,39 +352,40 @@ public class OPCUAClient : IDisposable
|
||||
dic_subscriptions.RemoveWhere(a => a.Key == subscriptionName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Callback(MonitoredItem monitoreditem, MonitoredItemNotificationEventArgs monitoredItemNotificationEventArgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var variableNode = ReadNode(monitoreditem.StartNodeId.ToString(), false);
|
||||
foreach (var value in monitoreditem.DequeueValues())
|
||||
if (m_session != null)
|
||||
{
|
||||
if (value.Value != null)
|
||||
var variableNode = ReadNode(monitoreditem.StartNodeId.ToString(), false);
|
||||
foreach (var value in monitoreditem.DequeueValues())
|
||||
{
|
||||
var data = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
|
||||
if (data == null && value.Value != null)
|
||||
if (value.Value != null)
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"{monitoreditem.StartNodeId}转换出错,原始值String为{value.Value}", null);
|
||||
var data1 = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
|
||||
var data = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
|
||||
if (data == null && value.Value != null)
|
||||
{
|
||||
UpdateStatus(3, DateTime.Now, $"{monitoreditem.StartNodeId}转换出错,原始值String为{value.Value}");
|
||||
var data1 = JsonUtils.Encode(m_session.MessageContext, TypeInfo.GetBuiltInType(variableNode.DataType, m_session.SystemContext.TypeTable), value.Value);
|
||||
}
|
||||
DataChangedHandler?.Invoke((variableNode, value, data));
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = JValue.CreateNull();
|
||||
DataChangedHandler?.Invoke((variableNode, value, data));
|
||||
}
|
||||
DataChangedHandler?.Invoke((variableNode, value, data));
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = JValue.CreateNull();
|
||||
DataChangedHandler?.Invoke((variableNode, value, data));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"{monitoreditem.StartNodeId}订阅处理错误", ex);
|
||||
UpdateStatus(3, DateTime.Now, $"{monitoreditem.StartNodeId}订阅处理错误,错误原因:" + ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -462,8 +511,8 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 连接
|
||||
|
||||
private ComplexTypeSystem typeSystem;
|
||||
|
||||
/// <summary>
|
||||
@@ -472,7 +521,6 @@ public class OPCUAClient : IDisposable
|
||||
public async Task ConnectAsync()
|
||||
{
|
||||
await ConnectAsync(OPCNode.OPCUrl);
|
||||
_logAction?.Invoke(1, this, $"连接成功", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -484,10 +532,10 @@ public class OPCUAClient : IDisposable
|
||||
// disconnect any existing session.
|
||||
if (m_session != null)
|
||||
{
|
||||
_logAction?.Invoke(1, this, $"主动断开连接", null);
|
||||
m_session = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new session.
|
||||
/// </summary>
|
||||
@@ -516,20 +564,24 @@ public class OPCUAClient : IDisposable
|
||||
//创建本地证书
|
||||
await m_application.CheckApplicationInstanceCertificate(true, 0, 1200);
|
||||
m_session = await Opc.Ua.Client.Session.Create(
|
||||
m_configuration,
|
||||
endpoint,
|
||||
false,
|
||||
OPCNode.CheckDomain,
|
||||
(string.IsNullOrEmpty(OPCUAName)) ? m_configuration.ApplicationName : OPCUAName,
|
||||
60000,
|
||||
userIdentity,
|
||||
Array.Empty<string>());
|
||||
|
||||
m_configuration,
|
||||
endpoint,
|
||||
false,
|
||||
OPCNode.CheckDomain,
|
||||
(string.IsNullOrEmpty(OPCUAName)) ? m_configuration.ApplicationName : OPCUAName,
|
||||
60000,
|
||||
userIdentity,
|
||||
Array.Empty<string>());
|
||||
typeSystem = new ComplexTypeSystem(m_session);
|
||||
|
||||
m_session.KeepAliveInterval = OPCNode.KeepAliveInterval == 0 ? 60000 : OPCNode.KeepAliveInterval;
|
||||
m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
|
||||
|
||||
// raise an event.
|
||||
DoConnectComplete(true);
|
||||
|
||||
UpdateStatus(2, DateTime.UtcNow, "Connected");
|
||||
|
||||
//如果是订阅模式,连接时添加订阅组
|
||||
if (OPCNode.ActiveSubscribe)
|
||||
await AddSubscriptionAsync(Guid.NewGuid().ToString(), Variables.ToArray(), OPCNode.LoadType);
|
||||
@@ -538,6 +590,9 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
private void PrivateDisconnect()
|
||||
{
|
||||
bool state = m_session?.Connected == true;
|
||||
|
||||
|
||||
if (m_reConnectHandler != null)
|
||||
{
|
||||
try { m_reConnectHandler.Dispose(); } catch { }
|
||||
@@ -549,8 +604,14 @@ public class OPCUAClient : IDisposable
|
||||
m_session.Close(10000);
|
||||
}
|
||||
|
||||
if (state)
|
||||
{
|
||||
UpdateStatus(2, DateTime.UtcNow, "Disconnected");
|
||||
DoConnectComplete(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 读取/写入
|
||||
@@ -593,7 +654,6 @@ public class OPCUAClient : IDisposable
|
||||
valuesToWrite.Add(valueToWrite);
|
||||
}
|
||||
|
||||
|
||||
var result = await m_session.WriteAsync(
|
||||
requestHeader: null,
|
||||
nodesToWrite: valuesToWrite, cancellationToken);
|
||||
@@ -601,7 +661,6 @@ public class OPCUAClient : IDisposable
|
||||
ClientBase.ValidateResponse(result.Results, valuesToWrite);
|
||||
ClientBase.ValidateDiagnosticInfos(result.DiagnosticInfos, valuesToWrite);
|
||||
|
||||
|
||||
var keys = writeInfoLists.Keys.ToList();
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
@@ -624,7 +683,6 @@ public class OPCUAClient : IDisposable
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -706,7 +764,6 @@ public class OPCUAClient : IDisposable
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从服务器读取节点
|
||||
/// </summary>
|
||||
@@ -729,18 +786,14 @@ public class OPCUAClient : IDisposable
|
||||
}
|
||||
else
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"获取服务器节点信息失败{nodes.Item2[i]}", null);
|
||||
UpdateStatus(3, DateTime.Now, $"获取服务器节点信息失败{nodes.Item2[i]}");
|
||||
}
|
||||
}
|
||||
return nodes.Item1.ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region 特性
|
||||
|
||||
/// <summary>
|
||||
@@ -805,7 +858,6 @@ public class OPCUAClient : IDisposable
|
||||
ResultMask = (uint)BrowseResultMask.All
|
||||
};
|
||||
nodesToBrowse.Add(nodeToBrowse);
|
||||
|
||||
}
|
||||
|
||||
return await ReadNoteAttributeAsync(nodesToBrowse, nodesToRead, cancellationToken);
|
||||
@@ -968,11 +1020,9 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
return nodeAttribute.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -991,7 +1041,6 @@ public class OPCUAClient : IDisposable
|
||||
throw new Exception(string.Format("验证证书失败,错误代码:{0}: {1}", eventArgs.Error.Code, eventArgs.Error.AdditionalInfo));
|
||||
}
|
||||
|
||||
|
||||
private async Task<Dictionary<string, List<OPCNodeAttribute>>> ReadNoteAttributeAsync(BrowseDescriptionCollection nodesToBrowse, ReadValueIdCollection nodesToRead, CancellationToken cancellationToken)
|
||||
{
|
||||
int startOfProperties = nodesToRead.Count;
|
||||
@@ -1068,7 +1117,6 @@ public class OPCUAClient : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (nodeAttributes.ContainsKey(nodeToRead.NodeId.ToString()))
|
||||
{
|
||||
nodeAttributes[nodeToRead.NodeId.ToString()].Add(item);
|
||||
@@ -1086,21 +1134,47 @@ public class OPCUAClient : IDisposable
|
||||
/// </summary>
|
||||
private void Server_ReconnectComplete(object sender, EventArgs e)
|
||||
{
|
||||
if (!Object.ReferenceEquals(sender, m_reConnectHandler))
|
||||
try
|
||||
{
|
||||
return;
|
||||
if (!Object.ReferenceEquals(sender, m_reConnectHandler))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_session = m_reConnectHandler.Session;
|
||||
m_reConnectHandler.Dispose();
|
||||
m_reConnectHandler = null;
|
||||
|
||||
// raise any additional notifications.
|
||||
m_ReconnectComplete?.Invoke(this, e);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
m_session = m_reConnectHandler.Session;
|
||||
m_reConnectHandler = null;
|
||||
|
||||
/// <summary>
|
||||
/// Report the client status
|
||||
/// </summary>
|
||||
/// <param name="logLevel">Whether the status represents an error. </param>
|
||||
/// <param name="time">The time associated with the status.</param>
|
||||
/// <param name="status">The status message.</param>
|
||||
/// <param name="args">Arguments used to format the status message.</param>
|
||||
private void UpdateStatus(int logLevel, DateTime time, string status, params object[] args)
|
||||
{
|
||||
m_OpcStatusChange?.Invoke(this, new OpcUaStatusEventArgs()
|
||||
{
|
||||
LogLevel = logLevel,
|
||||
Time = time.ToLocalTime(),
|
||||
Text = String.Format(status, args),
|
||||
});
|
||||
}
|
||||
|
||||
private void Session_KeepAlive(ISession session, KeepAliveEventArgs e)
|
||||
{
|
||||
lock (checkLock)
|
||||
{
|
||||
|
||||
if (!Object.ReferenceEquals(session, m_session))
|
||||
{
|
||||
return;
|
||||
@@ -1108,22 +1182,39 @@ public class OPCUAClient : IDisposable
|
||||
|
||||
if (ServiceResult.IsBad(e.Status))
|
||||
{
|
||||
_logAction?.Invoke(3, this, $"心跳检测错误:{e.Status}", null);
|
||||
if (m_session.KeepAliveInterval <= 0)
|
||||
{
|
||||
UpdateStatus(3, e.CurrentTime, "Communication Error ({0})", e.Status);
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateStatus(3, e.CurrentTime, "Reconnecting in {0}s", m_session.KeepAliveInterval / 1000);
|
||||
|
||||
if (m_reConnectHandler == null)
|
||||
{
|
||||
m_ReconnectStarting?.Invoke(this, e);
|
||||
|
||||
m_reConnectHandler = new SessionReconnectHandler();
|
||||
m_reConnectHandler.BeginReconnect(m_session, m_session.KeepAliveInterval, Server_ReconnectComplete);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// update status.
|
||||
UpdateStatus(0, e.CurrentTime, "Session_KeepAlive Connected [{0}]", session.Endpoint.EndpointUrl);
|
||||
|
||||
// raise any additional notifications.
|
||||
m_KeepAliveComplete?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Raises the connect complete event on the main GUI thread.
|
||||
/// </summary>
|
||||
private void DoConnectComplete(bool state)
|
||||
{
|
||||
m_ConnectComplete?.Invoke(this, state);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#region copyright
|
||||
#region copyright
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
@@ -8,11 +9,39 @@
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endregion
|
||||
|
||||
using Opc.Ua;
|
||||
|
||||
namespace ThingsGateway.Foundation.Adapter.OPCUA;
|
||||
|
||||
/// <summary>
|
||||
/// OPC UA的状态更新消息
|
||||
/// </summary>
|
||||
public class OpcUaStatusEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志等级,<br></br>
|
||||
/// 更为详细的步骤型日志输出 Trace = 0,<br></br>
|
||||
/// 调试信息日志Debug = 1,<br></br>
|
||||
/// 消息类日志输出 Info = 2,<br></br>
|
||||
/// 警告类日志输出 Warning = 3,<br></br>
|
||||
/// 错误类日志输出 Error = 4,<br></br>
|
||||
/// 不可控中断类日输出Critical = 5,
|
||||
/// </summary>
|
||||
public int LogLevel { get; set; }
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime Time { get; set; }
|
||||
/// <summary>
|
||||
/// 文本
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取属性过程中用于描述的
|
||||
/// </summary>
|
||||
@@ -22,6 +51,7 @@ public class OPCNodeAttribute
|
||||
/// 属性的名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作结果状态描述
|
||||
/// </summary>
|
||||
@@ -31,10 +61,9 @@ public class OPCNodeAttribute
|
||||
/// 属性的类型描述
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 属性的值,如果读取错误,返回文本描述
|
||||
/// </summary>
|
||||
public object Value { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,8 +27,7 @@ using System.Runtime.CompilerServices;
|
||||
namespace ThingsGateway.Foundation.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 具有释放的对象。
|
||||
/// 并未实现析构函数相关。
|
||||
/// 具有释放的对象。内部实现了GC.SuppressFinalize,但不包括析构函数相关。
|
||||
/// </summary>
|
||||
public partial class DisposableObject : IDisposable
|
||||
{
|
||||
@@ -65,11 +64,12 @@ namespace ThingsGateway.Foundation.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源。
|
||||
/// 释放资源。内部已经处理了<see cref="GC.SuppressFinalize(object)"/>
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,15 @@ namespace ThingsGateway.Foundation.Core
|
||||
return isPeriod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 累计增加一个计数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Increment()
|
||||
{
|
||||
return this.Increment(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置<see cref="Count"/>和<see cref="LastIncrement"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -47,14 +47,7 @@ namespace ThingsGateway.Foundation.Core
|
||||
/// </summary>
|
||||
public TimeSpan Period { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重置<see cref="Count"/>和<see cref="LastIncrement"/>
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this.m_count = 0;
|
||||
this.m_lastIncrement = default;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 累计增加计数
|
||||
@@ -78,5 +71,26 @@ namespace ThingsGateway.Foundation.Core
|
||||
Interlocked.Add(ref this.m_count, value);
|
||||
return isPeriod;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 累计增加一个计数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Increment()
|
||||
{
|
||||
return this.Increment(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置<see cref="Count"/>和<see cref="LastIncrement"/>
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
this.m_count = 0;
|
||||
this.m_lastIncrement = default;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -760,7 +760,15 @@ public class SerialSessionBase : BaseSerial, ISerialSession
|
||||
this.m_serialCore.Reset(serialPort);
|
||||
this.m_serialCore.OnReceived = this.HandleReceived;
|
||||
this.m_serialCore.OnBreakOut = this.BreakOut;
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MinBufferSizeProperty) is int minValue)
|
||||
{
|
||||
this.m_serialCore.MinBufferSize = minValue;
|
||||
}
|
||||
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MaxBufferSizeProperty) is int maxValue)
|
||||
{
|
||||
this.m_serialCore.MaxBufferSize = maxValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleReceived(SerialCore core, ByteBlock byteBlock)
|
||||
|
||||
@@ -227,6 +227,15 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
tcpCore.Reset(socket);
|
||||
tcpCore.OnReceived = this.HandleReceived;
|
||||
tcpCore.OnBreakOut = this.BreakOut;
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MinBufferSizeProperty) is int minValue)
|
||||
{
|
||||
tcpCore.MinBufferSize = minValue;
|
||||
}
|
||||
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MaxBufferSizeProperty) is int maxValue)
|
||||
{
|
||||
tcpCore.MaxBufferSize = maxValue;
|
||||
}
|
||||
this.m_tcpCore = tcpCore;
|
||||
}
|
||||
|
||||
|
||||
@@ -497,6 +497,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return this.GetIPPort();
|
||||
}
|
||||
private void BreakOut(TcpCore core, bool manual, string msg)
|
||||
{
|
||||
lock (this.SyncRoot)
|
||||
@@ -931,7 +936,15 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.m_tcpCore.Reset(socket);
|
||||
this.m_tcpCore.OnReceived = this.HandleReceived;
|
||||
this.m_tcpCore.OnBreakOut = this.BreakOut;
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MinBufferSizeProperty) is int minValue)
|
||||
{
|
||||
this.m_tcpCore.MinBufferSize = minValue;
|
||||
}
|
||||
|
||||
if (this.Config.GetValue(TouchSocketConfigExtension.MaxBufferSizeProperty) is int maxValue)
|
||||
{
|
||||
this.m_tcpCore.MaxBufferSize = maxValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleReceived(TcpCore core, ByteBlock byteBlock)
|
||||
|
||||
@@ -209,7 +209,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="e"></param>
|
||||
protected virtual Task OnDisconnecting(TClient socketClient, DisconnectEventArgs e)
|
||||
{
|
||||
if (this.Disconnected != null)
|
||||
if (this.Disconnecting != null)
|
||||
{
|
||||
return this.Disconnecting.Invoke(socketClient, e);
|
||||
}
|
||||
|
||||
@@ -155,6 +155,11 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <param name="tcpCore"></param>
|
||||
public void ReturnTcpCore(TcpCore tcpCore)
|
||||
{
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
tcpCore.SafeDispose();
|
||||
return;
|
||||
}
|
||||
this.m_tcpCores.Push(tcpCore);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,54 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
public static readonly DependencyProperty<Func<UdpDataHandlingAdapter>> UdpDataHandlingAdapterProperty = DependencyProperty<Func<UdpDataHandlingAdapter>>.Register("UdpDataHandlingAdapter", () => { return new NormalUdpDataHandlingAdapter(); });
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 最小缓存池尺寸
|
||||
/// 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int?> MinBufferSizeProperty = DependencyProperty<int?>.Register("MinBufferSize", default);
|
||||
|
||||
/// <summary>
|
||||
/// 最大缓存池尺寸
|
||||
/// 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<int?> MaxBufferSizeProperty = DependencyProperty<int?>.Register("MinBufferSize", default);
|
||||
|
||||
/// <summary>
|
||||
/// 最小缓存容量,默认缺省。
|
||||
/// <list type="number">
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig MinBufferSize(this TouchSocketConfig config, int value)
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, "数值不能小于1024");
|
||||
}
|
||||
config.SetValue(MinBufferSizeProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大缓存容量,默认缺省。
|
||||
/// <list type="number">
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig MaxBufferSize(this TouchSocketConfig config, int value)
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, "数值不能小于1024");
|
||||
}
|
||||
config.SetValue(MaxBufferSizeProperty, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送超时设定,单位毫秒,默认为0。意为禁用该配置。
|
||||
/// </summary>
|
||||
|
||||
@@ -22,7 +22,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
private readonly AsyncAutoResetEvent m_resetEventForRead = new AsyncAutoResetEvent(false);
|
||||
private ByteBlock m_byteBlock;
|
||||
private IRequestInfo m_requestInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Receiver
|
||||
/// </summary>
|
||||
~Receiver()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
/// <summary>
|
||||
/// Receiver
|
||||
/// </summary>
|
||||
@@ -74,9 +80,15 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
this.m_client.ClearReceiver();
|
||||
//this.m_resetEventForComplateRead.SafeDispose();
|
||||
this.m_resetEventForRead.SafeDispose();
|
||||
if (disposing)
|
||||
{
|
||||
this.m_client.ClearReceiver();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_resetEventForRead.SafeDispose();
|
||||
}
|
||||
|
||||
this.m_byteBlock = null;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.16</Version>
|
||||
<Version>3.0.0.20</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
|
||||
@@ -177,6 +177,8 @@ public class OPCUAClient : CollectBase
|
||||
if (_plc != null)
|
||||
{
|
||||
_plc.DataChangedHandler -= DataChangedHandler;
|
||||
_plc.OpcStatusChange -= _plc_OpcStatusChange;
|
||||
|
||||
_plc.Disconnect();
|
||||
_plc.SafeDispose();
|
||||
_plc = null;
|
||||
@@ -204,13 +206,19 @@ public class OPCUAClient : CollectBase
|
||||
};
|
||||
if (_plc == null)
|
||||
{
|
||||
_plc = new((arg1, arg2, arg3, arg4) => Log_Out((LogLevel)arg1, arg2, arg3, arg4));
|
||||
_plc = new();
|
||||
_plc.OpcStatusChange += _plc_OpcStatusChange;
|
||||
_plc.DataChangedHandler += DataChangedHandler;
|
||||
}
|
||||
|
||||
_plc.OPCNode = opcNode;
|
||||
}
|
||||
|
||||
private void _plc_OpcStatusChange(object sender, OpcUaStatusEventArgs e)
|
||||
{
|
||||
Log_Out((LogLevel)e.LogLevel, null, e.Text, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -36,16 +36,24 @@ public partial class OPCUAClientPage
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
OPC.OpcStatusChange -= OPC_OpcStatusChange;
|
||||
OPC.SafeDispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
OPC = new ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient(LogOut);
|
||||
OPC = new ThingsGateway.Foundation.Adapter.OPCUA.OPCUAClient();
|
||||
OPC.OpcStatusChange += OPC_OpcStatusChange;
|
||||
base.OnInitialized();
|
||||
}
|
||||
|
||||
private void OPC_OpcStatusChange(object sender, OpcUaStatusEventArgs e)
|
||||
{
|
||||
if (e.LogLevel > 0)
|
||||
LogAction?.Invoke((LogLevel)e.LogLevel, null, e.Text, null);
|
||||
}
|
||||
|
||||
private async Task ConnectAsync()
|
||||
{
|
||||
try
|
||||
@@ -75,6 +83,4 @@ public partial class OPCUAClientPage
|
||||
return OPC;
|
||||
}
|
||||
|
||||
private void LogOut(byte logLevel, object source, string message, Exception exception) => LogAction?.Invoke((LogLevel)logLevel, source, message, exception);
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.16</Version>
|
||||
<Version>3.0.0.20</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Authors>Diego</Authors>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>3.0.0.16</Version>
|
||||
<Version>3.0.0.20</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
|
||||
@@ -164,6 +164,7 @@ public class CollectDeviceThread : IAsyncDisposable
|
||||
var stoppingToken = StoppingTokens.Last().Token;
|
||||
DeviceTask = await Task.Factory.StartNew(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
var channelResult = CollectDeviceCores.FirstOrDefault().Driver.GetShareChannel();
|
||||
LoggerGroup log = CollectDeviceCores.FirstOrDefault().Driver.LogMessage;
|
||||
foreach (var device in CollectDeviceCores)
|
||||
|
||||
@@ -153,6 +153,7 @@ public class UploadDeviceThread : IAsyncDisposable
|
||||
var stoppingToken = StoppingTokens.Last().Token;
|
||||
DeviceTask = await Task.Factory.StartNew(async () =>
|
||||
{
|
||||
await Task.Yield();
|
||||
LoggerGroup log = UploadDeviceCores.FirstOrDefault().Driver.LogMessage;
|
||||
foreach (var device in UploadDeviceCores)
|
||||
{
|
||||
@@ -225,5 +226,7 @@ public class UploadDeviceThread : IAsyncDisposable
|
||||
|
||||
}
|
||||
, TaskCreationOptions.LongRunning);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export const language = ["en","zh"];
|
||||
export const removeDefaultStopWordFilter = false;
|
||||
export const removeDefaultStemmer = false;
|
||||
export { default as Mark } from "E:\\Tg\\ThingsGateway\\ThingsGateway-DEV\\handbook\\node_modules\\mark.js\\dist\\mark.js"
|
||||
export const searchIndexUrl = "search-index{dir}.json?_=590a19da";
|
||||
export const searchIndexUrl = "search-index{dir}.json?_=5f24d3ee";
|
||||
export const searchResultLimits = 8;
|
||||
export const searchResultContextMaxLength = 50;
|
||||
export const explicitSearchResultPath = true;
|
||||
|
||||
@@ -227,9 +227,9 @@
|
||||
"179": {
|
||||
"js": [
|
||||
{
|
||||
"file": "assets/js/main.4e65a7c4.js",
|
||||
"hash": "7245ddb629dafe73",
|
||||
"publicPath": "/thingsgateway-docs/assets/js/main.4e65a7c4.js"
|
||||
"file": "assets/js/main.cf42840d.js",
|
||||
"hash": "41e8aa8c7cbe401b",
|
||||
"publicPath": "/thingsgateway-docs/assets/js/main.cf42840d.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -299,9 +299,9 @@
|
||||
"1303": {
|
||||
"js": [
|
||||
{
|
||||
"file": "assets/js/runtime~main.7f6e9c09.js",
|
||||
"hash": "aedff306f0f845ba",
|
||||
"publicPath": "/thingsgateway-docs/assets/js/runtime~main.7f6e9c09.js"
|
||||
"file": "assets/js/runtime~main.2b19bbf8.js",
|
||||
"hash": "e48e0c0408aa1c4e",
|
||||
"publicPath": "/thingsgateway-docs/assets/js/runtime~main.2b19bbf8.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -326,9 +326,9 @@
|
||||
"1822": {
|
||||
"js": [
|
||||
{
|
||||
"file": "assets/js/f05a39b7.bfb8e652.js",
|
||||
"hash": "3d8f498000b417cb",
|
||||
"publicPath": "/thingsgateway-docs/assets/js/f05a39b7.bfb8e652.js"
|
||||
"file": "assets/js/f05a39b7.a300eca8.js",
|
||||
"hash": "67b94ba06477a5ab",
|
||||
"publicPath": "/thingsgateway-docs/assets/js/f05a39b7.a300eca8.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -619,9 +619,9 @@
|
||||
"8707": {
|
||||
"js": [
|
||||
{
|
||||
"file": "assets/js/4c79e569.3f1e7d8c.js",
|
||||
"hash": "5ca0c0dec325073e",
|
||||
"publicPath": "/thingsgateway-docs/assets/js/4c79e569.3f1e7d8c.js"
|
||||
"file": "assets/js/4c79e569.5c5c0d05.js",
|
||||
"hash": "e9c712a478ed50e6",
|
||||
"publicPath": "/thingsgateway-docs/assets/js/4c79e569.5c5c0d05.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
"tags": [],
|
||||
"version": "current",
|
||||
"lastUpdatedBy": "Kimdiego2098",
|
||||
"lastUpdatedAt": 1695729838,
|
||||
"formattedLastUpdatedAt": "Sep 26, 2023",
|
||||
"lastUpdatedAt": 1697449154,
|
||||
"formattedLastUpdatedAt": "Oct 16, 2023",
|
||||
"frontMatter": {
|
||||
"id": "enterprise",
|
||||
"title": "Pro版相关"
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
"editUrl": "https://gitee.com/diego2098/ThingsGateway/tree/master/handbook/docs/upgrade.mdx",
|
||||
"tags": [],
|
||||
"version": "current",
|
||||
"lastUpdatedBy": "Diego2098",
|
||||
"lastUpdatedAt": 1691418711,
|
||||
"formattedLastUpdatedAt": "Aug 7, 2023",
|
||||
"lastUpdatedBy": "Kimdiego2098",
|
||||
"lastUpdatedAt": 1697632930,
|
||||
"formattedLastUpdatedAt": "Oct 18, 2023",
|
||||
"frontMatter": {
|
||||
"id": "upgrade",
|
||||
"title": "历史更新"
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
handbook/build/assets/js/4c79e569.5c5c0d05.js
Normal file
1
handbook/build/assets/js/4c79e569.5c5c0d05.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -18,15 +18,31 @@ import Tag from "@site/src/components/Tag.js";
|
||||
|
||||
:::
|
||||
|
||||
## v2.1.0(未发布)
|
||||
|
||||
- <Tag>新增</Tag> 添加TDengine时序库存储
|
||||
## v3.0.0.20(已发布)
|
||||
|
||||
- <Tag>新增</Tag> 添加报警延时逻辑
|
||||
- <Tag>优化</Tag> 优化ModbusServer GC频繁的问题
|
||||
|
||||
- <Tag>新增</Tag> 添加采集数据延时确认逻辑
|
||||
|
||||
- <Tag>优化</Tag> 去除DateTimeOffset类型
|
||||
## v3.0.0.19(已发布)
|
||||
|
||||
- <Tag>新增</Tag> 添加TDengineDB时序库上传插件
|
||||
- <Tag>新增</Tag> 添加QuestDB时序库上传插件
|
||||
- <Tag>新增</Tag> 添加DLT645采集插件
|
||||
- <Tag>新增</Tag> 添加调试软件
|
||||
- <Tag>新增</Tag> 添加远程更新软件
|
||||
|
||||
- <Tag>优化</Tag> 优化OPCUA驱动
|
||||
- <Tag>优化</Tag> 优化Modbus驱动
|
||||
- <Tag>优化</Tag> 优化S7驱动
|
||||
- <Tag>优化</Tag> RPC服务
|
||||
- <Tag>优化</Tag> 其他人性化操作
|
||||
|
||||
- <Tag>调整</Tag> 内嵌TouckSocket
|
||||
|
||||
- <Tag>修复</Tag> 内存泄露
|
||||
- <Tag>修复</Tag> 串口断连/拔出/断电等情况,重新连接
|
||||
- <Tag>修复</Tag> 其他bug
|
||||
|
||||
|
||||
## v2.0.0(已发布)
|
||||
|
||||
Reference in New Issue
Block a user