Compare commits

..

23 Commits

Author SHA1 Message Date
Kimdiego2098
7e06f19bbc 更新5.0.0.5 2024-01-24 12:19:29 +08:00
Kimdiego2098
0b66c1f0d6 添加using 2024-01-24 11:15:32 +08:00
Kimdiego2098
ff2742ffd8 删除字节转换类的copynew方法 2024-01-24 10:11:10 +08:00
Kimdiego2098
70c2992a5f 调整命名空间 2024-01-24 09:45:13 +08:00
Kimdiego2098
4ac4ee6874 调整命名空间 2024-01-24 08:50:53 +08:00
Kimdiego2098
865164a404 删除多余代码 2024-01-24 08:49:01 +08:00
Diego2098
f9c8069ab2 调整DTU配置,增加心跳回应 2024-01-23 21:32:47 +08:00
Diego2098
2fbf5140e5 调整DTU配置,增加心跳回应 2024-01-23 21:09:57 +08:00
Kimdiego2098
0126f8144a 调整mqtt在线状态判断 2024-01-23 18:06:22 +08:00
Kimdiego2098
71383d7482 调整日志读取策略 2024-01-23 17:23:36 +08:00
Kimdiego2098
4d3bfc5f42 调整封装方法 2024-01-23 15:51:08 +08:00
Kimdiego2098
c173d217de 添加重启后台事件 2024-01-23 08:50:08 +08:00
Kimdiego2098
d2da9a039f 更新5.0.0.4 2024-01-22 23:13:02 +08:00
Kimdiego2098
c915edd458 S7握手失败时直接关闭连接 2024-01-22 23:03:03 +08:00
Kimdiego2098
504948452e 更新TD引用 2024-01-22 22:12:17 +08:00
Kimdiego2098
3daa6c7a54 修复空指针错误 2024-01-22 21:53:59 +08:00
Kimdiego2098
10cd1580a5 调整命名 2024-01-22 21:13:59 +08:00
Kimdiego2098
5b0876e106 修复缓存item没有默认构造函数导致的錯誤 2024-01-22 11:38:16 +08:00
Kimdiego2098
cfcdeaff01 调整常量位置 2024-01-22 11:24:37 +08:00
Kimdiego2098
7c34f233fd 更新文档 2024-01-22 09:50:38 +08:00
Kimdiego2098
686146a7d9 修复导入插件错误 2024-01-22 08:38:48 +08:00
Kimdiego2098
44732d5977 更新5.0.0.3 2024-01-21 22:48:30 +08:00
Kimdiego2098
05c3794cf7 修复属性为可空类型是,excek导入失败的问题 2024-01-21 22:48:04 +08:00
127 changed files with 454 additions and 426 deletions

8
doc/build/404.html vendored

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

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

View File

@@ -115,6 +115,16 @@ arraylen=2;
|报警文本| 对应显示的报警文本 ||
|报警约束| 动态解析的表达式 ,原始值的代码为raw计算值为true时才能产生报警 ||
:::tip `例子`
数值高高报警
变量值大于报警限值并且报警约束为true或者报警约束不存在时产生报警
比如设置高高限值为1其他默认当变量值大于1时产生报警
:::
### 业务属性配置项
<img src={require("@site/static/img/docs/添加变量2.png").default} />

View File

@@ -6,7 +6,7 @@
<LangVersion>11.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>5.0.0.2</Version>
<Version>5.0.0.5</Version>
<Authors>Diego</Authors>
<Company>Diego</Company>
<Product>Diego</Product>

View File

@@ -12,7 +12,7 @@
#endregion
namespace ThingsGateway.Admin.Core;
namespace ThingsGateway.Admin.Application;
/// <summary>
/// SignalR消息

View File

@@ -14,7 +14,7 @@
using System.ComponentModel;
namespace ThingsGateway.Admin.Core;
namespace ThingsGateway.Admin.Application;
/// <summary>
/// 会话信息

View File

@@ -12,7 +12,7 @@
#endregion
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// SqlSugar系统常量

View File

@@ -12,7 +12,7 @@
#endregion
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// 主键id基类

View File

@@ -12,7 +12,7 @@
#endregion
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// 实体种子数据接口

View File

@@ -12,7 +12,7 @@
#endregion
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// Linq分页泛型集合

View File

@@ -115,7 +115,7 @@ public static class ObjectExtension
/// <param name="type">类型</param>
/// <param name="generic">泛型类型</param>
/// <returns>bool</returns>
internal static bool HasImplementedRawGeneric(this Type type, Type generic)
public static bool HasImplementedRawGeneric(this Type type, Type generic)
{
// 检查接口类型
var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);

View File

@@ -15,7 +15,7 @@
using System.Linq.Expressions;
using System.Reflection;
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// Sqlsugar分页拓展类

View File

@@ -24,6 +24,4 @@ global using System.Collections.Generic;
global using System.Linq;
global using System.Threading.Tasks;
global using ThingsGateway.Admin.Application;
global using ThingsGateway.Admin.Core;
global using ThingsGateway.Core;

View File

@@ -20,7 +20,7 @@ using ThingsGateway.Core.Extension;
using Yitter.IdGenerator;
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// 数据库上下文对象

View File

@@ -14,7 +14,7 @@
using System.Linq.Expressions;
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// 仓储模式对象

View File

@@ -14,7 +14,7 @@
using Furion.ConfigurableOptions;
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// 初始化表配置

View File

@@ -7,7 +7,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.1" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.136" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.137" />
</ItemGroup>
<ItemGroup>

View File

@@ -15,7 +15,7 @@
using System.Collections;
using System.Reflection;
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// CodeFirst功能类
@@ -109,32 +109,6 @@ public static class CodeFirstUtils
}
}
/// <summary>
/// 判断类型是否实现某个泛型
/// </summary>
/// <param name="type">类型</param>
/// <param name="generic">泛型类型</param>
/// <returns>bool</returns>
public static bool HasImplementedRawGeneric(this Type type, Type generic)
{
// 检查接口类型
var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
if (isTheRawGenericType) return true;
// 检查类型
while (type != null && type != typeof(object))
{
isTheRawGenericType = IsTheRawGenericType(type);
if (isTheRawGenericType) return true;
type = type.BaseType ?? default;
}
return false;
// 判断逻辑
bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type);
}
/// <summary>
/// 排除SqlSugar忽略的列
/// </summary>

View File

@@ -14,7 +14,7 @@
using NewLife.Serialization;
namespace ThingsGateway.Admin.Application;
namespace ThingsGateway.Admin.Core;
/// <summary>
/// 种子数据工具类

View File

@@ -23,6 +23,13 @@ namespace ThingsGateway.Cache;
/// </summary>
public class LiteDBDefalutCacheItem<T> : IPrimaryIdEntity
{
/// <summary>
/// LiteDBDefalutCacheItem
/// </summary>
public LiteDBDefalutCacheItem()
{
}
/// <summary>
/// LiteDBDefalutCacheItem
/// </summary>

View File

@@ -157,14 +157,19 @@ public partial class AdapterDebugPage : AdapterDebugBase
}
else
{
var result = TextFileReader.LastLog(files.FirstOrDefault().FullName, 0);
if (result.IsSuccess)
_ = Task.Run(() =>
{
Messages = result.Content.Select(a => ((int)a.LogLevel, $"{a.LogTime} - {a.Message} {Environment.NewLine} {a.ExceptionString}")).ToList();
}
else
{
}
var result = TextFileReader.LastLog(files.FirstOrDefault().FullName, 0);
if (result.IsSuccess)
{
Messages = result.Content.Select(a => ((int)a.LogLevel, $"{a.LogTime} - {a.Message}")).ToList();
}
else
{
Messages = new List<(int, string)>();
}
});
await Task.Delay(1000);
}
}
}

View File

@@ -19,6 +19,7 @@ using Microsoft.AspNetCore.Components;
using ThingsGateway.Foundation;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace ThingsGateway.Demo
{
@@ -34,6 +35,7 @@ namespace ThingsGateway.Demo
{
if (ChannelData != item.Item)
{
ChannelData?.Channel?.Close();
ChannelData = item.Item;
await OnEditClick.InvokeAsync(ChannelData);
}
@@ -48,6 +50,7 @@ namespace ThingsGateway.Demo
{
if (ChannelData != channelData)
{
ChannelData?.Channel?.Close();
ChannelData = channelData;
ChannelConfigs.Default.Save(true, out _);
await OnEditClick.InvokeAsync(ChannelData);
@@ -59,6 +62,7 @@ namespace ThingsGateway.Demo
{
try
{
ChannelData?.Channel?.Close();
ChannelConfigs.Default.ChannelDatas.Remove(ChannelData);
ChannelData = null;
ChannelName = null;
@@ -95,6 +99,7 @@ namespace ThingsGateway.Demo
if (data != null)
{
ChannelData?.Channel?.Close();
ChannelConfigs.Default.ChannelDatas.Remove(ChannelData);
ChannelData = (ChannelData)data;
ChannelData.CreateChannel(ChannelData);

View File

@@ -35,6 +35,8 @@
<MTextField Class="ma-1" Outlined Style="max-width:150px" Dense HideDetails="@("auto")"
Label=@(AppService.I18n.T(_plc.Description(x => x.Password))) @bind-Value=@_plc.Password></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:150px" Dense HideDetails="@("auto")"
Label=@(AppService.I18n.T(_plc.Description(x => x.HeartbeatHexString))) @bind-Value=@_plc.HeartbeatHexString></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px"
@bind-Value="_plc.DataFormat" Label="@(AppService.I18n.T(_plc.Description(x => x.DataFormat)))"

View File

@@ -39,6 +39,8 @@
<MTextField Class="ma-1" Outlined Style="max-width:150px" Dense HideDetails="@("auto")"
Label=@(AppService.I18n.T(_plc.Description(x => x.Station))) @bind-Value=@_plc.Station></MTextField>
<MTextField Class="ma-1" Outlined Style="max-width:150px" Dense HideDetails="@("auto")"
Label=@(AppService.I18n.T(_plc.Description(x => x.HeartbeatHexString))) @bind-Value=@_plc.HeartbeatHexString></MTextField>
<MSelect Class="ma-1" Outlined Style="max-width:200px"
@bind-Value="_plc.DataFormat" Label="@(AppService.I18n.T(_plc.Description(x => x.DataFormat)))"

View File

@@ -12,7 +12,6 @@
<ProjectReference Include="..\foundation\ThingsGateway.Foundation.OpcDa\src\ThingsGateway.Foundation.OpcDa.csproj" />
<ProjectReference Include="..\foundation\ThingsGateway.Foundation.OpcUa\src\ThingsGateway.Foundation.OpcUa.csproj" />
<ProjectReference Include="..\foundation\ThingsGateway.Foundation.SiemensS7\src\ThingsGateway.Foundation.SiemensS7.csproj" />
<ProjectReference Include="..\foundation\ThingsGateway.Foundation\src\ThingsGateway.Foundation.csproj" />
<ProjectReference Include="..\ThingsGateway.Components\ThingsGateway.Components.csproj" />
<ProjectReference Include="..\ThingsGateway.Core\ThingsGateway.Core.csproj" />
</ItemGroup>
@@ -47,9 +46,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Service\" />
<Folder Include="wwwroot\" />
</ItemGroup>
</Project>

View File

@@ -2,5 +2,8 @@
"HardwareInfo": {
"Enable": true, //启用硬件信息获取
"TimeInterval": 10000 //更新间隔ms
},
"ChannelThread": {
"CycleInterval": 20 //最小循环间隔
}
}

View File

@@ -2,5 +2,8 @@
"HardwareInfo": {
"Enable": true, //启用硬件信息获取
"TimeInterval": 10000 //更新间隔ms
},
"ChannelThread": {
"CycleInterval": 20 //最小循环间隔
}
}

View File

@@ -173,6 +173,7 @@ public class VariableRunTime : Variable, IVariable
{
IsOnline = false;
Set(null);
VariableSource.LastErrorMessage = $"{Name} 转换表达式失败:{ex.Message}";
return new($"{Name} 转换表达式失败:{ex.Message}");
}
}

View File

@@ -30,7 +30,13 @@ public class ChannelThread
/// <summary>
/// 线程最小等待间隔时间
/// </summary>
public const int CycleInterval = 10;
public static volatile int CycleInterval = 10;
static ChannelThread()
{
var cycleInterval = App.GetConfig<int?>("ChannelThread:CycleInterval") ?? 10;
CycleInterval = cycleInterval < 10 ? 10 : cycleInterval;
}
/// <summary>
/// <inheritdoc cref="TouchSocket.Core.TouchSocketConfig"/>

View File

@@ -449,7 +449,7 @@ public class PluginService : IPluginService
foreach (var item in plugin.OtherFiles ?? new())
{
using var otherStream = item.OpenReadStream(maxFileSize);
using MemoryStream memoryStream1 = new MemoryStream();
MemoryStream memoryStream1 = new MemoryStream();
await otherStream.CopyToAsync(memoryStream1);
memoryStream1.Seek(0, SeekOrigin.Begin);
otherFilesStreams.Add((item.Name, memoryStream1));
@@ -491,6 +491,7 @@ public class PluginService : IPluginService
item.Item2.Seek(0, SeekOrigin.Begin);
using FileStream fs1 = new(fullDir.CombinePathOS(item.Item1), FileMode.Create);
await item.Item2.CopyToAsync(fs1);
await item.Item2.DisposeAsync();
}
}
finally

View File

@@ -8,8 +8,7 @@
<ItemGroup>
<PackageReference Include="SqlSugar.TDengineCore" Version="4.1.6">
<Private>false</Private>
<IncludeAssets> native;build;runtime </IncludeAssets>
</PackageReference>
</ItemGroup>

View File

@@ -117,7 +117,6 @@ public class AlarmWorker : BackgroundService
device.VariableRunTimes?.ForEach(v => { v.VariableCollectChange -= DeviceVariableChange; });
}
StoppingTokens.ParallelForEach(cancellationToken =>
{
_ = Task.Run(() =>

View File

@@ -78,6 +78,8 @@ public class CollectDeviceWorker : DeviceWorker
var businessDeviceHostService = WorkerUtil.GetWoker<BusinessDeviceWorker>();
await businessDeviceHostService.StartAsync();
await alarmHostService.StartAsync();
if (Start != null)
await Start.Invoke();
}
/// <summary>
@@ -89,6 +91,8 @@ public class CollectDeviceWorker : DeviceWorker
var businessDeviceHostService = WorkerUtil.GetWoker<BusinessDeviceWorker>();
await alarmHostService.StopAsync();
await businessDeviceHostService.StopAsync();
if (Stop != null)
await Stop.Invoke();
}
#endregion public
@@ -161,4 +165,9 @@ public class CollectDeviceWorker : DeviceWorker
}
#endregion worker服务
}
public event RestartEventHandler Stop;
public event RestartEventHandler Start;
}
public delegate Task RestartEventHandler();

View File

@@ -30,7 +30,7 @@ public partial class DeviceStatus
try
{
await Task.Delay(2000);
Execute();
await Execute();
}
catch
{
@@ -76,12 +76,12 @@ public partial class DeviceStatus
private RenderFragment _driverRender;
private object _importRef;
private void DeviceInfoOnClick(DriverBase item)
private async void DeviceInfoOnClick(DriverBase item)
{
if (_driverBaseItem != item)
{
_driverBaseItem = item;
Execute();
await Execute();
}
}
@@ -158,7 +158,7 @@ public partial class DeviceStatus
private List<(int, string)> Messages { get; set; } = new List<(int, string)>();
protected void Execute()
protected async Task Execute()
{
try
{
@@ -180,6 +180,7 @@ public partial class DeviceStatus
{
Messages = new List<(int, string)>();
}
await Task.Delay(1000);
}
}
else

View File

@@ -1,5 +1,6 @@
{
"ConfigurationScanDirectories": [ "Config" ],
"Urls": "http://0.0.0.0:7200" //监听地址
"Urls": "http://0.0.0.0:7200", //监听地址
"DetailedErrors": true
}

View File

@@ -1,5 +1,5 @@
{
"ConfigurationScanDirectories": [ "Config" ],
"Urls": "http://0.0.0.0:7200" //监听地址
"Urls": "http://0.0.0.0:7200", //监听地址
}

View File

@@ -35,14 +35,4 @@ public class DltConst
00010000 ()
"""
;
/// <summary>
/// Dtu-{0}-已连接
/// </summary>
public const string DtuConnected = "Dtu-{0}-Connected.";
/// <summary>
/// 客户端未连接或寄存器设置错误必须设置ID={DTU注册包}
/// </summary>
public const string DtuNoConnectedWaining = "The client is not connected or the register is set incorrectly. id={Dtu registration package} must be set.";
}

View File

@@ -85,20 +85,6 @@ public class Dlt645_2007BitConverter : ThingsGatewayBitConverter
return Convert.ToDouble(this.ToString(buffer, offset, buffer.Length));
}
/// <inheritdoc/>
public override IThingsGatewayBitConverter CopyNew()
{
return new Dlt645_2007BitConverter(EndianType)
{
DataFormat = DataFormat,
BcdFormat = BcdFormat,
Encoding = Encoding,
IsStringReverseByteWord = IsStringReverseByteWord,
StringLength = StringLength,
ArrayLength = ArrayLength,
};
}
/// <inheritdoc/>
public override string ToString(byte[] buffer)
{

View File

@@ -25,7 +25,14 @@ internal class Dlt645_2007Message : MessageBase, IMessage
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] heads)
{
BodyLength = -1;
return true;
if (SendBytes?.Length > 0)
{
BodyLength = -1;
return true;
}
else
{
return false;//不是主动请求的可能是心跳DTU包直接放弃
}
}
}

View File

@@ -65,6 +65,12 @@ public class Dlt645_2007Master : ProtocolBase
[Description("自动断开连接")]
public bool CheckClear { get; set; } = false;
/// <summary>
/// 心跳检测(大写16进制字符串)
/// </summary>
[Description("心跳检测")]
public string HeartbeatHexString { get; set; } = "FFFF8080";
/// <inheritdoc/>
public override string GetAddressDescription()
{
@@ -77,7 +83,7 @@ public class Dlt645_2007Master : ProtocolBase
switch (Channel.ChannelType)
{
case ChannelTypeEnum.TcpService:
Action<IPluginManager> action = null;
Action<IPluginManager> action = a => { };
if (CheckClear)
{
action = a => a.UseCheckClear()
@@ -89,16 +95,11 @@ public class Dlt645_2007Master : ProtocolBase
c.SafeClose("超时清理");
});
}
if (action == null)
action = a =>
{
a.Add<DtuPlugin>();
};
else
action += a =>
{
a.Add<DtuPlugin>();
};
action += a =>
{
a.Add<DtuPlugin>();
};
return action;
}
return base.ConfigurePlugins();
@@ -164,7 +165,7 @@ public class Dlt645_2007Master : ProtocolBase
return new();
}
else
return new OperResult<byte[]>(DltConst.DtuNoConnectedWaining);
return new OperResult<byte[]>(FoundationConst.DtuNoConnectedWaining);
}
else
{
@@ -181,7 +182,7 @@ public class Dlt645_2007Master : ProtocolBase
if (((TcpServiceBase)Channel).SocketClients.TryGetSocketClient($"ID={mAddress.SocketId}", out TgSocketClient? client))
return SendThenReturn(new SendMessage(commandResult), cancellationToken, client);
else
return new OperResult<byte[]>(DltConst.DtuNoConnectedWaining);
return new OperResult<byte[]>(FoundationConst.DtuNoConnectedWaining);
}
else
return SendThenReturn(new SendMessage(commandResult), cancellationToken);
@@ -225,7 +226,7 @@ public class Dlt645_2007Master : ProtocolBase
if (((TcpServiceBase)Channel).SocketClients.TryGetSocketClient($"ID={mAddress.SocketId}", out TgSocketClient? client))
return SendThenReturnAsync(new SendMessage(commandResult), cancellationToken, client);
else
return Task.FromResult(new OperResult<byte[]>(DltConst.DtuNoConnectedWaining));
return Task.FromResult(new OperResult<byte[]>(FoundationConst.DtuNoConnectedWaining));
}
else
return SendThenReturnAsync(new SendMessage(commandResult), cancellationToken);
@@ -475,17 +476,30 @@ public class Dlt645_2007Master : ProtocolBase
[PluginOption(Singleton = true)]
internal class DtuPlugin : PluginBase, ITcpReceivingPlugin
{
private Dlt645_2007Master _dlt645_2007Master;
public DtuPlugin(Dlt645_2007Master dlt645_2007Master)
{
_dlt645_2007Master = dlt645_2007Master;
}
public async Task OnTcpReceiving(ITcpClientBase client, ByteBlockEventArgs e)
{
if (client is ISocketClient socket)
{
var bytes = e.ByteBlock.ToArray();
if (!socket.Id.StartsWith("ID="))
{
ByteBlock byteBlock = e.ByteBlock;
var id = $"ID={Encoding.UTF8.GetString(byteBlock.ToArray())}";
client.Logger.Info(string.Format(DltConst.DtuConnected, id));
var id = $"ID={Encoding.UTF8.GetString(bytes)}";
client.Logger.Info(string.Format(FoundationConst.DtuConnected, id));
socket.ResetId(id);
}
if (_dlt645_2007Master.HeartbeatHexString == bytes.ToHexString())
{
//回应心跳包
socket.DefaultSend(bytes);
socket.Logger?.Trace($"{socket.ToString()}- {FoundationConst.Send}:{bytes.ToHexString(' ')}");
}
}
await e.InvokeNext();//如果本插件无法处理当前数据,请将数据转至下一个插件。
}

View File

@@ -35,16 +35,6 @@ public class ModbusConst
"""
;
/// <summary>
/// Dtu-{0}-已连接
/// </summary>
public const string DtuConnected = "Dtu-{0}-Connected.";
/// <summary>
/// 客户端未连接或寄存器设置错误必须设置ID={DTU注册包}
/// </summary>
public const string DtuNoConnectedWaining = "The client is not connected or the register is set incorrectly. id={Dtu registration package} must be set.";
/// <summary>
/// 功能码错误
/// </summary>

View File

@@ -25,7 +25,14 @@ internal class ModbusRtuMessage : MessageBase, IMessage
/// <inheritdoc/>
public override bool CheckHeadBytes(byte[] heads)
{
BodyLength = -1;
return true;
if (SendBytes?.Length > 0)
{
BodyLength = -1;
return true;
}
else
{
return false;//不是主动请求的可能是心跳DTU包直接放弃
}
}
}

View File

@@ -33,5 +33,7 @@ internal class ModbusTcpMessage : MessageBase, IMessage
BodyLength = num;
return true;
}
}

View File

@@ -76,6 +76,12 @@ public class ModbusMaster : ProtocolBase
[Description("自动断开连接")]
public bool CheckClear { get; set; } = false;
/// <summary>
/// 心跳检测(大写16进制字符串)
/// </summary>
[Description("心跳检测")]
public string HeartbeatHexString { get; set; } = "FFFF8080";
/// <inheritdoc/>
public override string GetAddressDescription()
{
@@ -88,7 +94,7 @@ public class ModbusMaster : ProtocolBase
switch (Channel.ChannelType)
{
case ChannelTypeEnum.TcpService:
Action<IPluginManager> action = null;
Action<IPluginManager> action = a => { };
if (CheckClear)
{
action = a => a.UseCheckClear()
@@ -100,16 +106,12 @@ public class ModbusMaster : ProtocolBase
c.SafeClose("超时清理");
});
}
if (action == null)
action = a =>
{
a.Add<DtuPlugin>();
};
else
action += a =>
{
a.Add<DtuPlugin>();
};
action += a =>
{
DtuPlugin dtuPlugin = new(this);
a.Add(dtuPlugin);
};
return action;
}
return base.ConfigurePlugins();
@@ -191,7 +193,7 @@ public class ModbusMaster : ProtocolBase
if (((TcpServiceBase)Channel).SocketClients.TryGetSocketClient($"ID={mAddress.SocketId}", out TgSocketClient? client))
return SendThenReturn(new SendMessage(commandResult), cancellationToken, client);
else
return new OperResult<byte[]>(ModbusConst.DtuNoConnectedWaining);
return new OperResult<byte[]>(FoundationConst.DtuNoConnectedWaining);
}
else
return SendThenReturn(new SendMessage(commandResult), cancellationToken);
@@ -219,7 +221,7 @@ public class ModbusMaster : ProtocolBase
if (((TcpServiceBase)Channel).SocketClients.TryGetSocketClient($"ID={mAddress.SocketId}", out TgSocketClient? client))
return SendThenReturnAsync(new SendMessage(commandResult), cancellationToken, client);
else
return Task.FromResult(new OperResult<byte[]>(ModbusConst.DtuNoConnectedWaining));
return Task.FromResult(new OperResult<byte[]>(FoundationConst.DtuNoConnectedWaining));
}
else
return SendThenReturnAsync(new SendMessage(commandResult), cancellationToken);
@@ -344,17 +346,30 @@ public class ModbusMaster : ProtocolBase
[PluginOption(Singleton = true)]
internal class DtuPlugin : PluginBase, ITcpReceivingPlugin
{
private ModbusMaster _modbusMaster;
public DtuPlugin(ModbusMaster modbusMaster)
{
this._modbusMaster = modbusMaster;
}
public async Task OnTcpReceiving(ITcpClientBase client, ByteBlockEventArgs e)
{
if (client is ISocketClient socket)
{
var bytes = e.ByteBlock.ToArray();
if (!socket.Id.StartsWith("ID="))
{
ByteBlock byteBlock = e.ByteBlock;
var id = $"ID={Encoding.UTF8.GetString(byteBlock.ToArray())}";
client.Logger.Info(string.Format(ModbusConst.DtuConnected, id));
var id = $"ID={Encoding.UTF8.GetString(bytes)}";
client.Logger.Info(string.Format(FoundationConst.DtuConnected, id));
socket.ResetId(id);
}
if (_modbusMaster.HeartbeatHexString == bytes.ToHexString())
{
//回应心跳包
socket.DefaultSend(bytes);
socket.Logger?.Trace($"{socket.ToString()}- {FoundationConst.Send}:{bytes.ToHexString(' ')}");
}
}
await e.InvokeNext();//如果本插件无法处理当前数据,请将数据转至下一个插件。
}

View File

@@ -120,7 +120,7 @@ public class ModbusSlave : ProtocolBase
switch (Channel.ChannelType)
{
case ChannelTypeEnum.TcpService:
Action<IPluginManager> action = null;
Action<IPluginManager> action = a => { };
if (CheckClear)
{
action = a => a.UseCheckClear()
@@ -132,16 +132,7 @@ public class ModbusSlave : ProtocolBase
c.SafeClose("超时清理");
});
}
if (action == null)
action = a =>
{
a.Add<DtuPlugin>();
};
else
action += a =>
{
a.Add<DtuPlugin>();
};
return action;
}
return base.ConfigurePlugins();

View File

@@ -356,6 +356,7 @@ public partial class SiemensS7Master : ProtocolBase
if (!result2.IsSuccess)
{
Logger?.LogWarning($"{channel.ToString()}PDU初始化失败-{result2.ErrorMessage},请检查机架号/槽号是否正确");
channel.Close();
return;
}
PduLength = ThingsGatewayBitConverter.ToUInt16(result2.Content.SelectLast(2), 0);
@@ -364,11 +365,13 @@ public partial class SiemensS7Master : ProtocolBase
catch (Exception ex)
{
Logger?.LogWarning($"{channel.ToString()}PDU初始化失败-{ex.Message},请检查机架号/槽号是否正确");
channel.Close();
return;
}
}
catch (Exception ex)
{
channel.Close();
Logger.Exception(ex);
}
finally

View File

@@ -111,7 +111,7 @@ namespace ThingsGateway.Foundation
{
base.Stop();
if (Monitor == null)
Logger.Info($"{Monitor.IPHost}{FoundationConst.ServiceStoped}");
Logger.Info($"{Monitor?.IPHost}{FoundationConst.ServiceStoped}");
}
else
{

Some files were not shown because too many files have changed in this diff Show More