Compare commits

..

5 Commits

Author SHA1 Message Date
Diego
ba008ef8ba 更新.NETVersion 2025-07-09 13:35:42 +08:00
Diego
28b533decf 10.9.34 2025-07-09 13:31:08 +08:00
Diego
9ee638c2f1 更新依赖包 2025-07-08 23:59:24 +08:00
Diego
d90fdbaf35 补充更新nuget包 2025-07-08 18:15:50 +08:00
Diego
b55e3db736 10.9.29 2025-07-08 17:55:37 +08:00
18 changed files with 94 additions and 139 deletions

View File

@@ -38,7 +38,7 @@
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<!--<PackageReference Include="Mapster" Version="7.4.0" />-->
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">

View File

@@ -1,7 +1,5 @@
using System.Collections.Concurrent;
using ThingsGateway.NewLife.Collections;
namespace ThingsGateway.NewLife.DictionaryExtensions;
/// <summary>并发字典扩展</summary>
@@ -106,58 +104,6 @@ public static class DictionaryExtensions
}
/// <summary>
/// 批量出队
/// </summary>
public static IEnumerable<T> ToIEnumerableWithDequeue<TKEY, T>(this ConcurrentDictionary<TKEY, T> values, int maxCount = 0)
{
if (values.IsEmpty) yield break;
if (maxCount <= 0)
{
maxCount = values.Count;
}
else
{
maxCount = Math.Min(maxCount, values.Count);
}
var keys = values.Keys;
foreach (var key in keys)
{
if (maxCount-- <= 0) break;
if (values.TryRemove(key, out var result))
{
yield return result;
}
}
}
/// <summary>
/// 批量出队
/// </summary>
public static IEnumerable<TKEY> ToIEnumerableWithDequeue<TKEY>(this ConcurrentHashSet<TKEY> values, int maxCount = 0)
{
if (values.IsEmpty) yield break;
if (maxCount <= 0)
{
maxCount = values.Count;
}
else
{
maxCount = Math.Min(maxCount, values.Count);
}
var keys = values.Keys;
foreach (var key in keys)
{
if (maxCount-- <= 0) break;
if (values.TryRemove(key))
{
yield return key;
}
}
}
/// <summary>
/// 批量出队
@@ -216,35 +162,9 @@ public static class DictionaryExtensions
}
}
/// <summary>
/// 批量出队
/// </summary>
public static List<TKEY> ToListWithDequeue<TKEY>(this ConcurrentHashSet<TKEY> values, int maxCount = 0)
{
List<TKEY> result = new();
if (values.IsEmpty) return result;
if (maxCount <= 0)
{
maxCount = values.Count;
}
else
{
maxCount = Math.Min(maxCount, values.Count);
}
var keys = values.Keys;
foreach (var key in keys)
{
if (maxCount-- <= 0) break;
if (values.TryRemove(key))
{
result.Add(key);
}
}
return result;
}
}

View File

@@ -1,13 +1,13 @@
<Project>
<PropertyGroup>
<PluginVersion>10.9.28</PluginVersion>
<ProPluginVersion>10.9.26</ProPluginVersion>
<DefaultVersion>10.9.28</DefaultVersion>
<AuthenticationVersion>2.9.13</AuthenticationVersion>
<SourceGeneratorVersion>10.9.13</SourceGeneratorVersion>
<NET8Version>8.0.17</NET8Version>
<NET9Version>9.0.6</NET9Version>
<PluginVersion>10.9.34</PluginVersion>
<ProPluginVersion>10.9.34</ProPluginVersion>
<DefaultVersion>10.9.34</DefaultVersion>
<AuthenticationVersion>2.9.16</AuthenticationVersion>
<SourceGeneratorVersion>10.9.15</SourceGeneratorVersion>
<NET8Version>8.0.18</NET8Version>
<NET9Version>9.0.7</NET9Version>
<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>
</PropertyGroup>

View File

@@ -10,8 +10,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="$(NET9Version)" />
<PackageReference Include="TouchSocket" Version="3.1.11" />
<PackageReference Include="TouchSocket.SerialPorts" Version="3.1.11" />
<PackageReference Include="TouchSocket" Version="3.1.12" />
<PackageReference Include="TouchSocket.SerialPorts" Version="3.1.12" />
</ItemGroup>
<ItemGroup>

View File

@@ -39,7 +39,8 @@ public interface IThingsGatewayBitConverter
[JsonProperty(ItemConverterType = typeof(NewtonsoftEncodingConverter))]
#endif
Encoding Encoding { get; set; }
public Encoding? Encoding { get; set; }
public Encoding EncodingValue { get; }
/// <summary>
/// 当前的Bcd编码类型

View File

@@ -29,13 +29,16 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
[System.Text.Json.Serialization.JsonConverter(typeof(EncodingConverter))]
[JsonConverter(typeof(NewtonsoftEncodingConverter))]
public Encoding Encoding { get; set; } = Encoding.UTF8;
public Encoding? Encoding { get; set; }
#else
[JsonConverter(typeof(NewtonsoftEncodingConverter))]
public Encoding Encoding { get; set; } = Encoding.UTF8;
public Encoding? Encoding { get; set; }
#endif
public Encoding EncodingValue => Encoding ?? Encoding.UTF8;
/// <inheritdoc/>
public DataFormatEnum DataFormat { get; set; }
@@ -239,7 +242,7 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
}
else
{
byte[] bytes = Encoding.GetBytes(value);
byte[] bytes = EncodingValue.GetBytes(value);
return IsStringReverseByteWord ? bytes.BytesReverseByWord().ArrayExpandToLength(StringLength.Value) : bytes.ArrayExpandToLength(StringLength.Value);
}
}
@@ -252,7 +255,7 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
}
else
{
byte[] bytes = Encoding.GetBytes(value);
byte[] bytes = EncodingValue.GetBytes(value);
return IsStringReverseByteWord ? bytes.BytesReverseByWord() : bytes;
}
}
@@ -366,8 +369,8 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
else
{
return IsStringReverseByteWord ?
Encoding.GetString(new ReadOnlySpan<byte>(buffer, offset, len).ToArray().BytesReverseByWord()).TrimEnd().Replace($"\0", "") :
Encoding.GetString(buffer, offset, len).TrimEnd().Replace($"\0", "");
EncodingValue.GetString(new ReadOnlySpan<byte>(buffer, offset, len).ToArray().BytesReverseByWord()).TrimEnd().Replace($"\0", "") :
EncodingValue.GetString(buffer, offset, len).TrimEnd().Replace($"\0", "");
}
}

View File

@@ -10,8 +10,8 @@
<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="Rougamo.Fody" Version="5.0.1" />
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
<PackageReference Include="TouchSocket.Dmtp" Version="3.1.11" />
<PackageReference Include="TouchSocket.WebApi.Swagger" Version="3.1.11" />
<PackageReference Include="TouchSocket.Dmtp" Version="3.1.12" />
<PackageReference Include="TouchSocket.WebApi.Swagger" Version="3.1.12" />
<PackageReference Include="ThingsGateway.Authentication" Version="$(AuthenticationVersion)" />
<!--<ProjectReference Include="..\..\PluginPro\ThingsGateway.Authentication\ThingsGateway.Authentication.csproj" />-->

View File

@@ -1419,7 +1419,7 @@ EventCallback.Factory.Create<MouseEventArgs>(this, async e =>
{
if (item.PluginType == PluginTypeEnum.Collect)
collectChannelDevices.Add(item, new());
else if (item.PluginType == PluginTypeEnum.Collect)
else if (item.PluginType == PluginTypeEnum.Business)
businessChannelDevices.Add(item, new());
else
otherChannelDevices.Add(item, new());

View File

@@ -8,8 +8,6 @@
// QQ群605534569
//------------------------------------------------------------------------------
using System.Text;
namespace ThingsGateway.Foundation.SiemensS7;
internal static class PackHelper
@@ -88,7 +86,7 @@ internal static class PackHelper
if (s7Address.WStringEnable)
{
it.ThingsGatewayBitConverter.Encoding = Encoding.Unicode;
//it.ThingsGatewayBitConverter.Encoding = Encoding.Unicode;
}
}
else
@@ -98,7 +96,7 @@ internal static class PackHelper
// 字符串在S7中前四个字节不属于实际内容
it.Index += 4;
lastLen = it.ThingsGatewayBitConverter.StringLength.Value + 4;
it.ThingsGatewayBitConverter.Encoding = Encoding.BigEndianUnicode;
//it.ThingsGatewayBitConverter.Encoding = Encoding.BigEndianUnicode;
}
else if (it.ThingsGatewayBitConverter.IsVariableStringLength)

View File

@@ -128,12 +128,12 @@ internal sealed partial class SiemensHelper
internal static async ValueTask<OperResult<string>> ReadWStringAsync(SiemensS7Master plc, string address, CancellationToken cancellationToken)
internal static async ValueTask<OperResult<string>> ReadWStringAsync(SiemensS7Master plc, string address, Encoding encoding, CancellationToken cancellationToken)
{
//先读取一次获取长度,再读取实际值
if (plc.SiemensS7Type != SiemensTypeEnum.S200Smart)
{
var encoding = Encoding.BigEndianUnicode;
encoding ??= Encoding.BigEndianUnicode;
var result1 = await plc.ReadAsync(address, 4, cancellationToken).ConfigureAwait(false);
if (!result1.IsSuccess)
{
@@ -155,7 +155,7 @@ internal sealed partial class SiemensHelper
}
else
{
var encoding = Encoding.Unicode;
encoding ??= Encoding.Unicode;
var result1 = await plc.ReadAsync(address, 1, cancellationToken).ConfigureAwait(false);
if (!result1.IsSuccess)
return new OperResult<string>(result1);
@@ -171,12 +171,12 @@ internal sealed partial class SiemensHelper
}
}
internal static async ValueTask<OperResult> WriteWStringAsync(SiemensS7Master plc, string address, string value, CancellationToken cancellationToken = default)
internal static async ValueTask<OperResult> WriteWStringAsync(SiemensS7Master plc, string address, string value, Encoding encoding, CancellationToken cancellationToken = default)
{
value ??= string.Empty;
if (plc.SiemensS7Type != SiemensTypeEnum.S200Smart)
{
byte[] inBytes1 = Encoding.BigEndianUnicode.GetBytes(value);
byte[] inBytes1 = (encoding ?? Encoding.BigEndianUnicode).GetBytes(value);
var result = await plc.ReadAsync(address, 4, cancellationToken).ConfigureAwait(false);
if (!result.IsSuccess) return result;
var num = plc.ThingsGatewayBitConverter.ToUInt16(result.Content, 0);
@@ -189,7 +189,7 @@ internal sealed partial class SiemensHelper
inBytes1
), DataTypeEnum.String, cancellationToken).ConfigureAwait(false);
}
byte[] inBytes2 = Encoding.Unicode.GetBytes(value);
byte[] inBytes2 = (encoding ?? Encoding.Unicode).GetBytes(value);
return await plc.WriteAsync(address, DataTransUtil.SpliceArray([(byte)value.Length], inBytes2), DataTypeEnum.String, cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -569,7 +569,7 @@ public partial class SiemensS7Master : DeviceBase
{
return new OperResult<string[]>(AppResource.StringLengthReadError);
}
var result = await SiemensHelper.ReadWStringAsync(this, address, cancellationToken).ConfigureAwait(false);
var result = await SiemensHelper.ReadWStringAsync(this, address, bitConverter.Encoding, cancellationToken).ConfigureAwait(false);
if (result.IsSuccess)
{
return OperResult.CreateSuccessResult(new string[] { result.Content });
@@ -585,7 +585,7 @@ public partial class SiemensS7Master : DeviceBase
{
return new OperResult<string[]>(AppResource.StringLengthReadError);
}
var result = await SiemensHelper.ReadStringAsync(this, address, bitConverter.Encoding, cancellationToken).ConfigureAwait(false);
var result = await SiemensHelper.ReadStringAsync(this, address, bitConverter.EncodingValue, cancellationToken).ConfigureAwait(false);
if (result.IsSuccess)
{
return OperResult.CreateSuccessResult(new string[] { result.Content });
@@ -608,11 +608,11 @@ public partial class SiemensS7Master : DeviceBase
if (((S7BitConverter)bitConverter)?.WStringEnable == true)
{
return SiemensHelper.WriteWStringAsync(this, address, value, cancellationToken);
return SiemensHelper.WriteWStringAsync(this, address, value, bitConverter.Encoding, cancellationToken);
}
if (bitConverter.IsVariableStringLength)
{
return SiemensHelper.WriteStringAsync(this, address, value, bitConverter.Encoding, cancellationToken);
return SiemensHelper.WriteStringAsync(this, address, value, bitConverter.EncodingValue, cancellationToken);
}
else
{

View File

@@ -147,9 +147,10 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariable, IDBH
{
if (_driverPropertys.IsReadDB)
{
var list = RealTimeVariables.ToListWithDequeue();
try
{
var varLists = RealTimeVariables.ToIEnumerableWithDequeue().Batch(100000);
var varLists = list.Batch(100000);
foreach (var varList in varLists)
{
var result = await UpdateAsync(varList, cancellationToken).ConfigureAwait(false);
@@ -166,6 +167,11 @@ public partial class SqlDBProducer : BusinessBaseWithCacheIntervalVariable, IDBH
if (success)
LogMessage?.LogWarning(ex);
success = false;
list.ForEach(variable =>
{
RealTimeVariables.AddOrUpdate(variable.Id, variable, (key, oldValue) => variable);
});
}
}

View File

@@ -172,7 +172,7 @@ public class ModbusSlave : BusinessBase
await Task.Delay(10000, cancellationToken).ConfigureAwait(false);
}
}
var list = ModbusVariableQueue.ToIEnumerableKVWithDequeue();
var list = ModbusVariableQueue.ToDictWithDequeue();
foreach (var item in list)
{
if (cancellationToken.IsCancellationRequested)

View File

@@ -8,6 +8,8 @@
// QQ群605534569
//------------------------------------------------------------------------------
using BootstrapBlazor.Components;
using Newtonsoft.Json.Linq;
using Opc.Ua;
@@ -226,7 +228,7 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
/// 更新变量
/// </summary>
/// <param name="variable"></param>
public void UpVariable(VariableRuntime variable)
public void UpVariable(VariableBasicData variable)
{
if (!NodeIdTags.TryGetValue($"{variable.DeviceName}.{variable.Name}", out var uaTag))
return;
@@ -314,6 +316,14 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
jToken.CalculateActualValueRank(),
jToken
);
if (dataValue == null)
{
_businessBase.LogMessage?.LogWarning($"{tag.NodeId} value is null , jToken: {jToken}");
}
else
{
_businessBase.LogMessage?.LogTrace($"{tag.NodeId} value {dataValue} , jToken: {jToken}");
}
newValue = dataValue;
success = true;
}
@@ -337,7 +347,6 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
else
tag.ValueRank = ValueRanks.Scalar;
var tp = elementType ?? value?.GetType() ?? typeof(string);
tag.DataType = DataNodeType(tp);
@@ -493,8 +502,18 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
UserWriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description,
ValueRank = ValueRanks.Scalar,
Id = variableRuntime.Id,
DataType = DataNodeType(variableRuntime),
};
var type = DataNodeType(variableRuntime);
if (type != null)
{
variable.DataType = type;
variable.IsDataTypeInit = true;
var elementType = variableRuntime.Value?.GetType()?.GetElementTypeEx();
if (elementType != null)
variable.ValueRank = ValueRanks.OneOrMoreDimensions;
else
variable.ValueRank = ValueRanks.Scalar;
}
var service = dbDrivers.FirstOrDefault(a => GlobalData.ContainsVariable(a.DeviceId, variableRuntime));
var level = ThingsGatewayNodeManager.ProtectTypeTrans(variableRuntime, service != null);
variable.AccessLevel = level;
@@ -940,20 +959,24 @@ public class ThingsGatewayNodeManager : CustomNodeManager2
/// </summary>
/// <param name="variableRuntime"></param>
/// <returns></returns>
private NodeId DataNodeType(VariableRuntime variableRuntime)
private NodeId? DataNodeType(VariableRuntime variableRuntime)
{
var str = variableRuntime.GetPropertyValue(_businessBase.DeviceId, nameof(OpcUaServerVariableProperty.DataType)) ?? "";
Type tp;
if (Enum.TryParse(str, out DataTypeEnum result))
{
tp = result.GetSystemType();
return DataNodeType(tp);
}
else
{
tp = variableRuntime.Value?.GetType() ?? variableRuntime.DataType.GetSystemType(); ;
tp = variableRuntime.Value?.GetType();
if (tp != null)
{
return DataNodeType(tp);
}
}
return DataNodeType(tp);
return null;
}

View File

@@ -14,9 +14,10 @@ using Microsoft.Extensions.Logging;
using Opc.Ua;
using Opc.Ua.Configuration;
using System.Collections.Concurrent;
using ThingsGateway.Extension.Generic;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Collections;
using ThingsGateway.NewLife.DictionaryExtensions;
using TouchSocket.Core;
@@ -43,7 +44,7 @@ public partial class OpcUaServer : BusinessBase
protected override BusinessPropertyBase _businessPropertyBase => _driverPropertys;
protected IStringLocalizer Localizer { get; private set; }
private ConcurrentHashSet<long> CollectVariableRuntimes { get; set; } = new();
private ConcurrentDictionary<long, VariableBasicData> CollectVariableRuntimes { get; set; } = new();
private static readonly string[] separator = new string[] { ";" };
@@ -155,7 +156,12 @@ public partial class OpcUaServer : BusinessBase
{
// 启动服务器。
await m_application.CheckApplicationInstanceCertificates(true, 1200, cancellationToken).ConfigureAwait(false);
await m_application.Start(m_server).ConfigureAwait(false);
IdVariableRuntimes.ForEach(a =>
{
VariableValueChange(a.Value, a.Value.AdaptVariableBasicData());
});
await base.ProtectedStartAsync(cancellationToken).ConfigureAwait(false);
}
@@ -167,10 +173,11 @@ public partial class OpcUaServer : BusinessBase
{
try
{
await Task.Delay(3000, cancellationToken).ConfigureAwait(false);
await Task.Delay(2000, cancellationToken).ConfigureAwait(false);
await m_application.CheckApplicationInstanceCertificates(true, 1200, cancellationToken).ConfigureAwait(false);
await m_application.Start(m_server).ConfigureAwait(false);
connect_success = true;
await Task.Delay(2000, cancellationToken).ConfigureAwait(false);
IdVariableRuntimes.ForEach(a =>
{
VariableValueChange(a.Value, a.Value.AdaptVariableBasicData());
@@ -191,10 +198,7 @@ public partial class OpcUaServer : BusinessBase
{
if (!cancellationToken.IsCancellationRequested)
{
if (IdVariableRuntimes.TryGetValue(item, out var variableRuntime) && variableRuntime != null)
{
m_server?.NodeManager?.UpVariable(variableRuntime);
}
m_server?.NodeManager?.UpVariable(item);
}
else
{
@@ -407,12 +411,12 @@ public partial class OpcUaServer : BusinessBase
}
private void VariableValueChange(VariableRuntime variableRuntime, VariableBasicData variableData)
{
if (CurrentDevice.Pause)
return;
//if (CurrentDevice.Pause)
// return;
if (TaskSchedulerLoop?.Stoped == true) return;
if (DisposedValue) return;
if (IdVariableRuntimes.ContainsKey(variableData.Id))
CollectVariableRuntimes.TryAdd(variableData.Id);
CollectVariableRuntimes.AddOrUpdate(variableData.Id, variableData, (a, b) => variableData);
else
{

View File

@@ -1,7 +1,7 @@
<Project>
<ItemGroup>
<PackageReference Include="ThingsGateway.Plugin.Synchronization" Version="$(ProPluginVersion)" GeneratePathProperty="true">
<PackageReference Include="ThingsGateway.Plugin.SyncBridge" Version="$(ProPluginVersion)" GeneratePathProperty="true">
<Private>false</Private>
<IncludeAssets> native;</IncludeAssets>
</PackageReference>
@@ -64,7 +64,7 @@
<PkgThingsGateway_Plugin_SECSPackageFiles Include="$(PkgThingsGateway_Plugin_SECS)\Content\$(PluginTargetFramework)\**\*.*" />
<PkgThingsGateway_Plugin_TS550PackageFiles Include="$(PkgThingsGateway_Plugin_TS550)\Content\$(PluginTargetFramework)\**\*.*" />
<PkgThingsGateway_Plugin_VigorPackageFiles Include="$(PkgThingsGateway_Plugin_Vigor)\Content\$(PluginTargetFramework)\**\*.*" />
<PkgThingsGateway_Plugin_SynchronizationPackageFiles Include="$(PkgThingsGateway_Plugin_Synchronization)\Content\$(PluginTargetFramework)\**\*.*" />
<PkgThingsGateway_Plugin_SyncBridgePackageFiles Include="$(PkgThingsGateway_Plugin_SyncBridge)\Content\$(PluginTargetFramework)\**\*.*" />
</ItemGroup>
<PropertyGroup>
@@ -91,7 +91,7 @@
<Copy SourceFiles="@(PkgThingsGateway_Plugin_TS550PackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.TS550%(RecursiveDir)" />
<Copy SourceFiles="@(PkgThingsGateway_Plugin_VigorPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.Vigor%(RecursiveDir)" />
<Copy SourceFiles="@(PkgThingsGateway_Plugin_VigorPackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.Synchronization%(RecursiveDir)" />
<Copy SourceFiles="@(PkgThingsGateway_Plugin_SyncBridgePackageFiles)" DestinationFolder="$(PluginFolder)ThingsGateway.Plugin.SyncBridge%(RecursiveDir)" />
</Target>
</Project>

View File

@@ -1,7 +1,7 @@
<Project>
<ItemGroup>
<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.Synchronization\ThingsGateway.Plugin.Synchronization.csproj" />
<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.SyncBridge\ThingsGateway.Plugin.SyncBridge.csproj" />
<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.AllenBradleyCip\ThingsGateway.Plugin.AllenBradleyCip.csproj" />
<ProjectReference Include="..\PluginPro\ThingsGateway.Plugin.BACnet\ThingsGateway.Plugin.BACnet.csproj" />

View File

@@ -16,7 +16,7 @@
<ItemGroup>
<PackageReference Include="TouchSocket.Dmtp" Version="3.1.11" />
<PackageReference Include="TouchSocket.Dmtp" Version="3.1.12" />
<PackageReference Include="Riok.Mapperly" Version="4.2.1" ExcludeAssets="runtime" PrivateAssets="all" />
</ItemGroup>