Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a533286658 | ||
![]() |
e59f91cd82 | ||
![]() |
5f8b85d8a4 | ||
![]() |
47c7b88436 | ||
![]() |
90006782f2 | ||
![]() |
c3d49cbe70 | ||
![]() |
112323a360 | ||
![]() |
9d08c90fda | ||
![]() |
602d24deec | ||
![]() |
a2b9f66785 | ||
![]() |
7cbf289b50 | ||
![]() |
4097da79a5 | ||
![]() |
91b7ae554f | ||
![]() |
3121aa2542 | ||
![]() |
4bf895e6e1 | ||
![]() |
0c5489e920 | ||
![]() |
d63c3aaa80 |
101
framework/ThingsGateway - Admin.sln
Normal file
101
framework/ThingsGateway - Admin.sln
Normal file
@@ -0,0 +1,101 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.6.33927.249
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin", "admin", "{4E66C22C-0636-4949-BF6A-9E3BBE1550BA}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
admin\Directory.Build.props = admin\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Components", "admin\ThingsGateway.Components\ThingsGateway.Components.csproj", "{0A891D8E-23B3-46AD-8D30-565EE5004F93}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Core", "admin\ThingsGateway.Core\ThingsGateway.Core.csproj", "{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Core", "admin\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj", "{5DA3D2BD-6768-4479-B52F-49E022EFF310}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Blazor", "admin\ThingsGateway.Admin.Blazor\ThingsGateway.Admin.Blazor.csproj", "{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.Application", "admin\ThingsGateway.Admin.Application\ThingsGateway.Admin.Application.csproj", "{D6685A42-2712-417A-92C5-5EFF90B9FA94}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Admin.ApiController", "admin\ThingsGateway.Admin.ApiController\ThingsGateway.Admin.ApiController.csproj", "{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web", "web", "{F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
web\Directory.Build.props = web\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Core", "web\ThingsGateway.Web.Core\ThingsGateway.Web.Core.csproj", "{D37EC028-EA46-4510-8261-6E780A906314}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Web.Entry", "web\ThingsGateway.Web.Entry\ThingsGateway.Web.Entry.csproj", "{C5F662EB-991F-438D-BF61-EF87E7371C04}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\.gitignore = ..\.gitignore
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Foundation", "foundation\ThingsGateway.Foundation\ThingsGateway.Foundation.csproj", "{6961511A-8787-42AF-827D-B630B2AF4791}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "foundation", "foundation", "{268A1A81-2685-47E1-9986-5934A58A31A4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D37EC028-EA46-4510-8261-6E780A906314}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{0A891D8E-23B3-46AD-8D30-565EE5004F93} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{A712EAEE-94F2-4F01-8C1C-2EC802280DD7} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{5DA3D2BD-6768-4479-B52F-49E022EFF310} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{8DD5DF98-7FDE-4B49-8661-AEB44D923CFE} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{D6685A42-2712-417A-92C5-5EFF90B9FA94} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{0D17D801-6DAA-4FD1-9A99-F9F07FA6BA88} = {4E66C22C-0636-4949-BF6A-9E3BBE1550BA}
|
||||
{D37EC028-EA46-4510-8261-6E780A906314} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{C5F662EB-991F-438D-BF61-EF87E7371C04} = {F0C9A8CB-231B-45E0-B91B-4FEF7EF47197}
|
||||
{6961511A-8787-42AF-827D-B630B2AF4791} = {268A1A81-2685-47E1-9986-5934A58A31A4}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@@ -82,6 +82,7 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{97B23D8B-C6C0-4746-A21F-C7B49354B284}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\.gitignore = ..\.gitignore
|
||||
..\README.md = ..\README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.Kafka", "plugin\ThingsGateway.Plugin.Kafka\ThingsGateway.Plugin.Kafka.csproj", "{E4B8B8E6-FAE7-43BA-9A51-33A3CD9FB825}"
|
||||
@@ -102,6 +103,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCDA"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.OPCUA", "plugin\ThingsGateway.Plugin.OPCUA\ThingsGateway.Plugin.OPCUA.csproj", "{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThingsGateway.Plugin.SQLHisAlarm", "plugin\ThingsGateway.Plugin.SQLHisAlarm\ThingsGateway.Plugin.SQLHisAlarm.csproj", "{0947E6C0-6371-4483-B0ED-191FB5073151}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -236,6 +239,10 @@ Global
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -273,6 +280,7 @@ Global
|
||||
{AC4295F2-AB2F-4137-99EF-80FA5C83896B} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{9DA9AED3-9572-4378-A2A6-4D792D67ADDC} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{FD4969DB-3CCE-4CCF-BAE4-1BE8A3F40812} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
{0947E6C0-6371-4483-B0ED-191FB5073151} = {E65490B8-D2E2-4693-B39C-15703B1EBFBB}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C49B2D3E-6818-4E28-91B7-6E4E7E264BBB}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
|
||||
<Version>4.0.0.0</Version>
|
||||
<Version>4.0.0.3</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Authors>Diego</Authors>
|
||||
|
@@ -86,7 +86,7 @@ public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
|
||||
Id = 22222222222229,
|
||||
Category = ConfigConst.SYS_CONFIGBASEDEFAULT,
|
||||
ConfigKey = ConfigConst.CONFIG_PAGETAB,
|
||||
ConfigValue = "false",
|
||||
ConfigValue = "true",
|
||||
Remark = "开启标签页",
|
||||
SortCode = 7,
|
||||
},
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ThingsGateway.Admin.Core\ThingsGateway.Admin.Core.csproj" />
|
||||
<PackageReference Include="MiniExcel" Version="1.31.2" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.5" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.6" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@@ -5,8 +5,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.1.4" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.117" />
|
||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.1.5" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.122" />
|
||||
<PackageReference Include="UAParser" Version="3.1.47" />
|
||||
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
|
||||
</ItemGroup>
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Furion.Pure" Version="4.9.1.4" />
|
||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.1.4" />
|
||||
<PackageReference Include="Furion.Pure" Version="4.9.1.5" />
|
||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.1.5" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
|
||||
<Version>4.0.0.0</Version>
|
||||
<Version>4.0.0.3</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Authors>Diego</Authors>
|
||||
<Product>ThingsGateway</Product>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>4.0.0.0</Version>
|
||||
<Version>4.0.0.3</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TargetFrameworks>net45;netstandard2.0;net6.0;net8.0;</TargetFrameworks>
|
||||
|
@@ -17,6 +17,10 @@ namespace ThingsGateway.Foundation.Adapter.Modbus
|
||||
/// <inheritdoc/>
|
||||
internal interface IModbusServer : IReadWrite
|
||||
{
|
||||
/// <summary>
|
||||
/// 外部写入数据后,是否写入内存(下次读取实时更新,否则需要内部调用Write)
|
||||
/// </summary>
|
||||
public bool WriteMemory { get; set; }
|
||||
/// <summary>
|
||||
/// 读写锁
|
||||
/// </summary>
|
||||
|
@@ -18,15 +18,19 @@ namespace ThingsGateway.Foundation.Adapter.Modbus;
|
||||
/// </summary>
|
||||
public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase, IModbusServer
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ModbusSerialServer(SerialSession serialSession) : base(serialSession)
|
||||
{
|
||||
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
|
||||
RegisterByteLength = 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读写锁
|
||||
/// </summary>
|
||||
public EasyLock EasyLock { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
|
||||
/// </summary>
|
||||
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, ISenderClient, Task<OperResult>> OnWriteData { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public bool IsRtu => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<byte, ByteBlock> ModbusServer01ByteBlocks { get; set; } = new();
|
||||
@@ -39,22 +43,22 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase, IModbusServ
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<byte, ByteBlock> ModbusServer04ByteBlocks { get; set; } = new();
|
||||
/// <inheritdoc/>
|
||||
public ModbusSerialServer(SerialSession serialSession) : base(serialSession)
|
||||
{
|
||||
ThingsGatewayBitConverter = new ThingsGatewayBitConverter(EndianType.Big);
|
||||
RegisterByteLength = 2;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool MulStation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收外部写入时,传出变量地址/写入字节组/转换规则/客户端
|
||||
/// </summary>
|
||||
public Func<ModbusAddress, byte[], IThingsGatewayBitConverter, ISenderClient, Task<OperResult>> OnWriteData { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte Station { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
public bool IsRtu => true;
|
||||
|
||||
|
||||
/// </summary>
|
||||
public bool WriteMemory { get; set; }
|
||||
/// <inheritdoc/>
|
||||
public override void Dispose()
|
||||
{
|
||||
@@ -87,6 +91,17 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase, IModbusServ
|
||||
return $"{base.GetAddressDescription()}{Environment.NewLine}{ModbusHelper.GetAddressDescription()}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Init(ModbusAddress mAddress)
|
||||
{
|
||||
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override List<T> LoadSourceRead<T, T2>(List<T2> deviceVariables, int maxPack, int defaultIntervalTime)
|
||||
{
|
||||
@@ -161,35 +176,4 @@ public class ModbusSerialServer : ReadWriteDevicesSerialSessionBase, IModbusServ
|
||||
Logger.LogError(ex, ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Init(ModbusAddress mAddress)
|
||||
{
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a =>
|
||||
{
|
||||
var data = new ByteBlock(ushort.MaxValue * 2);
|
||||
data.SetLength(ushort.MaxValue * 2);
|
||||
return data;
|
||||
});
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a =>
|
||||
{
|
||||
var data = new ByteBlock(ushort.MaxValue * 2);
|
||||
data.SetLength(ushort.MaxValue * 2);
|
||||
return data;
|
||||
});
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a =>
|
||||
{
|
||||
var data = new ByteBlock(ushort.MaxValue * 2);
|
||||
data.SetLength(ushort.MaxValue * 2);
|
||||
return data;
|
||||
});
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a =>
|
||||
{
|
||||
var data = new ByteBlock(ushort.MaxValue * 2);
|
||||
data.SetLength(ushort.MaxValue * 2);
|
||||
return data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -236,15 +236,17 @@ internal static class ModbusServerHelpers
|
||||
if ((await modbusServer.OnWriteData(modbusServerMessage.ModbusAddress, modbusServerMessage.Content, modbusServer.ThingsGatewayBitConverter, client)).IsSuccess)
|
||||
{
|
||||
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
|
||||
//var result = modbusServer.Write(modbusServerMessage.ModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
|
||||
//if (result.IsSuccess)
|
||||
//{
|
||||
// WriteSuccess(modbusServer, modbusServerMessage);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// WriteError(modbusServer, modbusServerMessage);
|
||||
//}
|
||||
if (modbusServer.WriteMemory)
|
||||
{
|
||||
var result = modbusServer.Write(modbusServerMessage.ModbusAddress.ToString(), coreData.ByteToBoolArray(modbusServerMessage.Length));
|
||||
if (result.IsSuccess)
|
||||
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
|
||||
else
|
||||
WriteError(modbusServer.IsRtu, client, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -273,16 +275,16 @@ internal static class ModbusServerHelpers
|
||||
|
||||
if ((await modbusServer.OnWriteData(modbusServerMessage.ModbusAddress, modbusServerMessage.Content, modbusServer.ThingsGatewayBitConverter, client)).IsSuccess)
|
||||
{
|
||||
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
|
||||
//var result = modbusServer.Write(modbusServerMessage.ModbusAddress.ToString(), coreData);
|
||||
//if (result.IsSuccess)
|
||||
//{
|
||||
// WriteSuccess(modbusServer, modbusServerMessage);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// WriteError(modbusServer, modbusServerMessage);
|
||||
//}
|
||||
if (modbusServer.WriteMemory)
|
||||
{
|
||||
var result = modbusServer.Write(modbusServerMessage.ModbusAddress.ToString(), coreData);
|
||||
if (result.IsSuccess)
|
||||
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
|
||||
else
|
||||
WriteError(modbusServer.IsRtu, client, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
WriteSuccess(modbusServer.IsRtu, client, modbusServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -19,11 +19,6 @@ namespace ThingsGateway.Foundation.Adapter.Modbus;
|
||||
/// </summary>
|
||||
public class ModbusTcpServer : ReadWriteDevicesTcpServerBase, IModbusServer
|
||||
{
|
||||
/// <summary>
|
||||
/// 读写锁
|
||||
/// </summary>
|
||||
public EasyLock EasyLock { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ModbusTcpServer(TcpService tcpService) : base(tcpService)
|
||||
{
|
||||
@@ -31,6 +26,10 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase, IModbusServer
|
||||
RegisterByteLength = 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读写锁
|
||||
/// </summary>
|
||||
public EasyLock EasyLock { get; } = new();
|
||||
/// <inheritdoc/>
|
||||
public bool IsRtu => false;
|
||||
|
||||
@@ -69,6 +68,10 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase, IModbusServer
|
||||
/// </summary>
|
||||
[Description("默认站点")]
|
||||
public byte Station { get; set; } = 1;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public bool WriteMemory { get; set; }
|
||||
|
||||
|
||||
|
||||
@@ -107,30 +110,12 @@ public class ModbusTcpServer : ReadWriteDevicesTcpServerBase, IModbusServer
|
||||
/// <inheritdoc/>
|
||||
public void Init(ModbusAddress mAddress)
|
||||
{
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a =>
|
||||
{
|
||||
var data = new ByteBlock(ushort.MaxValue * 2);
|
||||
data.SetLength(ushort.MaxValue * 2);
|
||||
return data;
|
||||
});
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a =>
|
||||
{
|
||||
var data = new ByteBlock(ushort.MaxValue * 2);
|
||||
data.SetLength(ushort.MaxValue * 2);
|
||||
return data;
|
||||
});
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a =>
|
||||
{
|
||||
var data = new ByteBlock(ushort.MaxValue * 2);
|
||||
data.SetLength(ushort.MaxValue * 2);
|
||||
return data;
|
||||
});
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a =>
|
||||
{
|
||||
var data = new ByteBlock(ushort.MaxValue * 2);
|
||||
data.SetLength(ushort.MaxValue * 2);
|
||||
return data;
|
||||
});
|
||||
|
||||
ModbusServer01ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
|
||||
ModbusServer02ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
|
||||
ModbusServer03ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
|
||||
ModbusServer04ByteBlocks.GetOrAdd(mAddress.Station, a => new ByteBlock(new byte[ushort.MaxValue * 2]));
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@@ -440,6 +440,7 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
|
||||
}
|
||||
finally
|
||||
{
|
||||
SetDataAdapter();
|
||||
await base.Connected(client, e);
|
||||
}
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ namespace ThingsGateway.Foundation.Extension.String;
|
||||
public static class StringExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换布尔值
|
||||
/// 转换布尔值,注意 1,0,on,off ,true,false 都会对应转换
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
|
@@ -338,7 +338,8 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
this.m_online = true;
|
||||
this.SetSocket(socket);
|
||||
this.BeginReceive();
|
||||
_ = Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
|
||||
this.PrivateOnConnected(new ConnectedEventArgs()).GetFalseAwaitResult();
|
||||
//_ = Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -394,7 +395,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
{
|
||||
throw new TimeoutException("连接超时");
|
||||
}
|
||||
Success(socket);
|
||||
await Success(socket);
|
||||
#else
|
||||
|
||||
using CancellationTokenSource cancellationTokenSource = new();
|
||||
@@ -411,7 +412,7 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
else
|
||||
{
|
||||
Success(socket);
|
||||
await Success(socket);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -424,12 +425,13 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
|
||||
|
||||
#endif
|
||||
void Success(Socket socket)
|
||||
async Task Success(Socket socket)
|
||||
{
|
||||
this.m_online = true;
|
||||
this.SetSocket(socket);
|
||||
this.BeginReceive();
|
||||
_ = Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
|
||||
await this.PrivateOnConnected(new ConnectedEventArgs());
|
||||
//_ = Task.Factory.StartNew(this.PrivateOnConnected, new ConnectedEventArgs());
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
@@ -186,6 +186,10 @@ namespace ThingsGateway.Foundation.Sockets
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_cancellationTokenSource = null;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>4.0.0.0</Version>
|
||||
<Version>4.0.0.3</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
|
||||
|
@@ -10,22 +10,15 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 上传插件
|
||||
/// </summary>
|
||||
public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
|
||||
public abstract class UpLoadBaseWithCache : UpLoadBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc/><br></br>
|
||||
@@ -33,50 +26,17 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
|
||||
/// </summary>
|
||||
public override DriverPropertyBase DriverPropertys => _uploadPropertyWithCache;
|
||||
|
||||
/// <summary>
|
||||
/// mapster配置
|
||||
/// </summary>
|
||||
protected virtual TypeAdapterConfig _config { get; set; }
|
||||
/// <summary>
|
||||
/// 是否需要设备上传,默认true
|
||||
/// </summary>
|
||||
protected virtual bool _device { get; } = true;
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="DriverPropertys"/>
|
||||
/// </summary>
|
||||
protected abstract UploadPropertyWithCache _uploadPropertyWithCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要变量上传,默认true
|
||||
/// </summary>
|
||||
protected virtual bool _variable { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 离线缓存
|
||||
/// </summary>
|
||||
protected LiteDBCache CacheDb { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
|
||||
_globalDeviceData?.CollectDevices?.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange -= DeviceStatusChange;
|
||||
});
|
||||
CacheDb?.Litedb?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Init(DeviceRunTime device)
|
||||
{
|
||||
base.Init(device);
|
||||
@@ -93,6 +53,20 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
|
||||
CollectDevices = _globalDeviceData.CollectDevices.Where(a => device.DeviceVariableRunTimes.Select(b => b.DeviceId).Contains(a.Id)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
CacheDb?.Litedb?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
@@ -101,167 +75,21 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
|
||||
protected override void Init(ISenderClient client = null)
|
||||
{
|
||||
CacheDb = new LiteDBCache(DeviceId.ToString(), CurrentDevice.PluginName);
|
||||
if (!_uploadPropertyWithCache.IsInterval)
|
||||
{
|
||||
if (_device)
|
||||
CollectDevices.ForEach(a => { a.DeviceStatusChange += DeviceStatusChange; });
|
||||
if (_variable)
|
||||
CurrentDevice.DeviceVariableRunTimes.ForEach(a => { a.VariableValueChange += VariableValueChange; });
|
||||
}
|
||||
|
||||
if (_uploadPropertyWithCache.CycleInterval <= 100) _uploadPropertyWithCache.CycleInterval = 100;
|
||||
if (_uploadPropertyWithCache.UploadInterval <= 1000) _uploadPropertyWithCache.UploadInterval = 1000;
|
||||
_exVariableTimerTick = new(_uploadPropertyWithCache.UploadInterval);
|
||||
_exDeviceTimerTick = new(_uploadPropertyWithCache.UploadInterval);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task ProtectedBeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_token = cancellationToken;
|
||||
_ = Task.Factory.StartNew(IntervalInsert);
|
||||
_ = Task.Factory.StartNew(CheckCacheDb);
|
||||
return base.ProtectedBeforStartAsync(cancellationToken);
|
||||
}
|
||||
#region 缓存操作
|
||||
|
||||
/// <summary>
|
||||
/// 设备内存队列
|
||||
/// </summary>
|
||||
protected CancellationToken _token;
|
||||
|
||||
protected ConcurrentQueue<DeviceT> _collectDeviceRunTimes = new();
|
||||
/// <summary>
|
||||
/// 变量内存队列
|
||||
/// </summary>
|
||||
|
||||
protected ConcurrentQueue<VariableT> _collectVariableRunTimes = new();
|
||||
|
||||
protected TimerTick _exDeviceTimerTick;
|
||||
|
||||
protected TimerTick _exVariableTimerTick;
|
||||
|
||||
private CancellationToken _token;
|
||||
protected abstract void AddCache(List<CacheItem> cacheItems, IEnumerable<VariableT> dev);
|
||||
|
||||
protected abstract void AddCache(List<CacheItem> cacheItems, IEnumerable<DeviceT> dev);
|
||||
|
||||
/// <summary>
|
||||
/// 添加设备队列,超限后会入缓存
|
||||
/// </summary>
|
||||
/// <param name="deviceData"></param>
|
||||
protected void AddDeviceQueue(DeviceT deviceData)
|
||||
{
|
||||
//检测队列长度,超限存入缓存数据库
|
||||
if (_collectDeviceRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
List<DeviceT> list = null;
|
||||
lock (_collectDeviceRunTimes)
|
||||
{
|
||||
if (_collectDeviceRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
list = _collectDeviceRunTimes.ToListWithDequeue();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (list != null)
|
||||
{
|
||||
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
|
||||
var cacheItems = new List<CacheItem>();
|
||||
AddCache(devData, cacheItems);
|
||||
if (cacheItems.Count > 0)
|
||||
CacheDb.Cache.Insert(cacheItems);
|
||||
}
|
||||
}
|
||||
|
||||
_collectDeviceRunTimes.Enqueue(deviceData);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加变量队列,超限后会入缓存
|
||||
/// </summary>
|
||||
/// <param name="variableData"></param>
|
||||
protected void AddVariableQueue(VariableT variableData)
|
||||
{
|
||||
//检测队列长度,超限存入缓存数据库
|
||||
if (_collectVariableRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
List<VariableT> list = null;
|
||||
lock (_collectVariableRunTimes)
|
||||
{
|
||||
if (_collectVariableRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
list = _collectVariableRunTimes.ToListWithDequeue();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (list != null)
|
||||
{
|
||||
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
|
||||
var cacheItems = new List<CacheItem>();
|
||||
AddCache(devData, cacheItems);
|
||||
|
||||
if (cacheItems.Count > 0)
|
||||
CacheDb.Cache.Insert(cacheItems);
|
||||
}
|
||||
}
|
||||
|
||||
_collectVariableRunTimes.Enqueue(variableData);
|
||||
|
||||
}
|
||||
|
||||
protected virtual void DeviceStatusChange(DeviceRunTime collectDeviceRunTime)
|
||||
{
|
||||
if (!CurrentDevice.KeepRun)
|
||||
return;
|
||||
if (_device)
|
||||
if (_uploadPropertyWithCache?.IsInterval != true)
|
||||
{
|
||||
AddDeviceQueue(collectDeviceRunTime.Adapt<DeviceT>(_config ?? TypeAdapterConfig.GlobalSettings));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void VariableValueChange(DeviceVariableRunTime deviceVariableRunTime)
|
||||
{
|
||||
if (!CurrentDevice.KeepRun)
|
||||
return;
|
||||
if (_variable)
|
||||
if (_uploadPropertyWithCache?.IsInterval != true)
|
||||
{
|
||||
AddVariableQueue(deviceVariableRunTime.Adapt<VariableT>(_config ?? TypeAdapterConfig.GlobalSettings));
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCache(IEnumerable<IEnumerable<VariableT>> devData, List<CacheItem> cacheItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var dev in devData)
|
||||
{
|
||||
AddCache(cacheItems, dev);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "缓存失败");
|
||||
}
|
||||
}
|
||||
private void AddCache(IEnumerable<IEnumerable<DeviceT>> devData, List<CacheItem> cacheItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var dev in devData)
|
||||
{
|
||||
AddCache(cacheItems, dev);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "缓存失败");
|
||||
}
|
||||
}
|
||||
private async Task CheckCacheDb()
|
||||
{
|
||||
while (!_token.IsCancellationRequested)
|
||||
@@ -269,7 +97,6 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
|
||||
try
|
||||
{
|
||||
CacheDb.DeleteOldData(_uploadPropertyWithCache.CahceMaxLength);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -278,58 +105,6 @@ public abstract class UpLoadBaseWithCache<DeviceT, VariableT> : UpLoadBase
|
||||
await Delay(30000, _token);
|
||||
}
|
||||
}
|
||||
private async Task IntervalInsert()
|
||||
{
|
||||
while (!_token.IsCancellationRequested)
|
||||
{
|
||||
|
||||
if (CurrentDevice?.KeepRun == false)
|
||||
{
|
||||
await Delay(_uploadPropertyWithCache.CycleInterval, _token);
|
||||
continue;
|
||||
}
|
||||
//间隔上传
|
||||
if (_uploadPropertyWithCache.IsInterval)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_variable)
|
||||
if (_exVariableTimerTick.IsTickHappen())
|
||||
{
|
||||
//间隔推送全部变量
|
||||
var varList = CurrentDevice.DeviceVariableRunTimes.Adapt<List<VariableT>>(_config ?? TypeAdapterConfig.GlobalSettings);
|
||||
foreach (var variableData in varList)
|
||||
{
|
||||
AddVariableQueue(variableData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "添加队列失败");
|
||||
}
|
||||
try
|
||||
{
|
||||
if (_device)
|
||||
if (_exDeviceTimerTick.IsTickHappen())
|
||||
{
|
||||
var devList = CollectDevices.Adapt<List<DeviceT>>(_config ?? TypeAdapterConfig.GlobalSettings);
|
||||
foreach (var devData in devList)
|
||||
{
|
||||
AddDeviceQueue(devData);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "添加队列失败");
|
||||
}
|
||||
}
|
||||
|
||||
await Delay(_uploadPropertyWithCache.CycleInterval, _token);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,334 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 上传插件
|
||||
/// </summary>
|
||||
public abstract class UpLoadBaseWithCacheT<DeviceT, VariableT> : UpLoadBase
|
||||
{
|
||||
/// <summary>
|
||||
/// <inheritdoc/><br></br>
|
||||
/// 实现<see cref="_uploadPropertyWithCache"/>
|
||||
/// </summary>
|
||||
public override DriverPropertyBase DriverPropertys => _uploadPropertyWithCache;
|
||||
|
||||
/// <summary>
|
||||
/// mapster配置
|
||||
/// </summary>
|
||||
protected virtual TypeAdapterConfig _config { get; set; }
|
||||
/// <summary>
|
||||
/// 是否需要设备上传,默认true
|
||||
/// </summary>
|
||||
protected virtual bool _device { get; } = true;
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="DriverPropertys"/>
|
||||
/// </summary>
|
||||
protected abstract UploadPropertyWithCacheT _uploadPropertyWithCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要变量上传,默认true
|
||||
/// </summary>
|
||||
protected virtual bool _variable { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 离线缓存
|
||||
/// </summary>
|
||||
protected LiteDBCache CacheDb { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
|
||||
_globalDeviceData?.CollectDevices?.ForEach(a =>
|
||||
{
|
||||
a.DeviceStatusChange -= DeviceStatusChange;
|
||||
});
|
||||
CacheDb?.Litedb?.SafeDispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Init(DeviceRunTime device)
|
||||
{
|
||||
base.Init(device);
|
||||
if (_uploadPropertyWithCache.IsAllVariable)
|
||||
{
|
||||
device.DeviceVariableRunTimes = _globalDeviceData.AllVariables;
|
||||
CollectDevices = _globalDeviceData.CollectDevices.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
var variables = _globalDeviceData.AllVariables.Where(a =>
|
||||
a.VariablePropertys.ContainsKey(device.Id)).ToList();
|
||||
device.DeviceVariableRunTimes = variables;
|
||||
CollectDevices = _globalDeviceData.CollectDevices.Where(a => device.DeviceVariableRunTimes.Select(b => b.DeviceId).Contains(a.Id)).ToList();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="device">当前设备</param>
|
||||
/// <param name="client">链路,共享链路时生效</param>
|
||||
protected override void Init(ISenderClient client = null)
|
||||
{
|
||||
CacheDb = new LiteDBCache(DeviceId.ToString(), CurrentDevice.PluginName);
|
||||
if (!_uploadPropertyWithCache.IsInterval)
|
||||
{
|
||||
if (_device)
|
||||
CollectDevices.ForEach(a => { a.DeviceStatusChange += DeviceStatusChange; });
|
||||
if (_variable)
|
||||
CurrentDevice.DeviceVariableRunTimes.ForEach(a => { a.VariableValueChange += VariableValueChange; });
|
||||
}
|
||||
|
||||
if (_uploadPropertyWithCache.CycleInterval <= 100) _uploadPropertyWithCache.CycleInterval = 100;
|
||||
if (_uploadPropertyWithCache.UploadInterval <= 1000) _uploadPropertyWithCache.UploadInterval = 1000;
|
||||
_exVariableTimerTick = new(_uploadPropertyWithCache.UploadInterval);
|
||||
_exDeviceTimerTick = new(_uploadPropertyWithCache.UploadInterval);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override Task ProtectedBeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_token = cancellationToken;
|
||||
_ = Task.Factory.StartNew(IntervalInsert);
|
||||
_ = Task.Factory.StartNew(CheckCacheDb);
|
||||
return base.ProtectedBeforStartAsync(cancellationToken);
|
||||
}
|
||||
#region 缓存操作
|
||||
|
||||
/// <summary>
|
||||
/// 设备内存队列
|
||||
/// </summary>
|
||||
|
||||
protected ConcurrentQueue<DeviceT> _collectDeviceRunTimes = new();
|
||||
/// <summary>
|
||||
/// 变量内存队列
|
||||
/// </summary>
|
||||
|
||||
protected ConcurrentQueue<VariableT> _collectVariableRunTimes = new();
|
||||
|
||||
protected TimerTick _exDeviceTimerTick;
|
||||
|
||||
protected TimerTick _exVariableTimerTick;
|
||||
|
||||
private CancellationToken _token;
|
||||
protected abstract void AddCache(List<CacheItem> cacheItems, IEnumerable<VariableT> dev);
|
||||
|
||||
protected abstract void AddCache(List<CacheItem> cacheItems, IEnumerable<DeviceT> dev);
|
||||
|
||||
/// <summary>
|
||||
/// 添加设备队列,超限后会入缓存
|
||||
/// </summary>
|
||||
/// <param name="deviceData"></param>
|
||||
private void AddDeviceQueue(DeviceT deviceData)
|
||||
{
|
||||
//检测队列长度,超限存入缓存数据库
|
||||
if (_collectDeviceRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
List<DeviceT> list = null;
|
||||
lock (_collectDeviceRunTimes)
|
||||
{
|
||||
if (_collectDeviceRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
list = _collectDeviceRunTimes.ToListWithDequeue();
|
||||
}
|
||||
|
||||
}
|
||||
if (list != null)
|
||||
{
|
||||
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
|
||||
var cacheItems = new List<CacheItem>();
|
||||
AddCache(devData, cacheItems);
|
||||
if (cacheItems.Count > 0)
|
||||
CacheDb.Cache.Insert(cacheItems);
|
||||
}
|
||||
}
|
||||
|
||||
_collectDeviceRunTimes.Enqueue(deviceData);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加变量队列,超限后会入缓存
|
||||
/// </summary>
|
||||
/// <param name="variableData"></param>
|
||||
private void AddVariableQueue(VariableT variableData)
|
||||
{
|
||||
//检测队列长度,超限存入缓存数据库
|
||||
if (_collectVariableRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
List<VariableT> list = null;
|
||||
lock (_collectVariableRunTimes)
|
||||
{
|
||||
if (_collectVariableRunTimes.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
list = _collectVariableRunTimes.ToListWithDequeue();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (list != null)
|
||||
{
|
||||
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
|
||||
var cacheItems = new List<CacheItem>();
|
||||
AddCache(devData, cacheItems);
|
||||
|
||||
if (cacheItems.Count > 0)
|
||||
CacheDb.Cache.Insert(cacheItems);
|
||||
}
|
||||
}
|
||||
|
||||
_collectVariableRunTimes.Enqueue(variableData);
|
||||
|
||||
}
|
||||
|
||||
protected virtual void DeviceStatusChange(DeviceRunTime collectDeviceRunTime)
|
||||
{
|
||||
if (!CurrentDevice.KeepRun)
|
||||
return;
|
||||
if (_device)
|
||||
if (_uploadPropertyWithCache?.IsInterval != true)
|
||||
{
|
||||
AddDeviceQueue(collectDeviceRunTime.Adapt<DeviceT>(_config ?? TypeAdapterConfig.GlobalSettings));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void VariableValueChange(DeviceVariableRunTime deviceVariableRunTime)
|
||||
{
|
||||
if (!CurrentDevice.KeepRun)
|
||||
return;
|
||||
if (_variable)
|
||||
if (_uploadPropertyWithCache?.IsInterval != true)
|
||||
{
|
||||
AddVariableQueue(deviceVariableRunTime.Adapt<VariableT>(_config ?? TypeAdapterConfig.GlobalSettings));
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCache(IEnumerable<IEnumerable<VariableT>> devData, List<CacheItem> cacheItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var dev in devData)
|
||||
{
|
||||
AddCache(cacheItems, dev);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "缓存失败");
|
||||
}
|
||||
}
|
||||
private void AddCache(IEnumerable<IEnumerable<DeviceT>> devData, List<CacheItem> cacheItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var dev in devData)
|
||||
{
|
||||
AddCache(cacheItems, dev);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "缓存失败");
|
||||
}
|
||||
}
|
||||
private async Task CheckCacheDb()
|
||||
{
|
||||
while (!_token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
CacheDb.DeleteOldData(_uploadPropertyWithCache.CahceMaxLength);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "删除缓存失败");
|
||||
}
|
||||
await Delay(30000, _token);
|
||||
}
|
||||
}
|
||||
private async Task IntervalInsert()
|
||||
{
|
||||
while (!_token.IsCancellationRequested)
|
||||
{
|
||||
|
||||
if (CurrentDevice?.KeepRun == false)
|
||||
{
|
||||
await Delay(_uploadPropertyWithCache.CycleInterval, _token);
|
||||
continue;
|
||||
}
|
||||
//间隔上传
|
||||
if (_uploadPropertyWithCache.IsInterval)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_variable)
|
||||
if (_exVariableTimerTick.IsTickHappen())
|
||||
{
|
||||
//间隔推送全部变量
|
||||
var varList = CurrentDevice.DeviceVariableRunTimes.Adapt<List<VariableT>>(_config ?? TypeAdapterConfig.GlobalSettings);
|
||||
foreach (var variableData in varList)
|
||||
{
|
||||
AddVariableQueue(variableData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "添加队列失败");
|
||||
}
|
||||
try
|
||||
{
|
||||
if (_device)
|
||||
if (_exDeviceTimerTick.IsTickHappen())
|
||||
{
|
||||
var devList = CollectDevices.Adapt<List<DeviceT>>(_config ?? TypeAdapterConfig.GlobalSettings);
|
||||
foreach (var devData in devList)
|
||||
{
|
||||
AddDeviceQueue(devData);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "添加队列失败");
|
||||
}
|
||||
}
|
||||
|
||||
await Delay(_uploadPropertyWithCache.CycleInterval, _token);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
@@ -39,18 +39,7 @@ public class UploadPropertyWithCache : DriverPropertyBase
|
||||
[DeviceProperty("列表分割大小", "默认1千条")]
|
||||
public virtual int SplitSize { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 是否间隔上传
|
||||
/// </summary>
|
||||
[DeviceProperty("是否间隔上传", "False时为变化检测上传")]
|
||||
public virtual bool IsInterval { get; set; } = false;
|
||||
/// <summary>
|
||||
/// 上传间隔时间
|
||||
/// </summary>
|
||||
[DeviceProperty("上传间隔时间", "最小1000ms")]
|
||||
public virtual int UploadInterval { get; set; } = 1000;
|
||||
|
||||
[DeviceProperty("是否选择全部变量", "")] public bool IsAllVariable { get; set; } = false;
|
||||
[DeviceProperty("是否选择全部变量", "")] public virtual bool IsAllVariable { get; set; } = false;
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,56 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class UploadPropertyWithCacheT : DriverPropertyBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 线程循环间隔
|
||||
/// </summary>
|
||||
[DeviceProperty("线程循环间隔", "最小10ms")]
|
||||
public virtual int CycleInterval { get; set; } = 1000;
|
||||
/// <summary>
|
||||
/// 内存队列最大条数
|
||||
/// </summary>
|
||||
[DeviceProperty("内存队列最大条数", "默认2w条")]
|
||||
public virtual int QueueMaxCount { get; set; } = 20000;
|
||||
/// <summary>
|
||||
/// 离线缓存大小限制
|
||||
/// </summary>
|
||||
[DeviceProperty("离线缓存文件大小限制", "默认1024mb")]
|
||||
public virtual int CahceMaxLength { get; set; } = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// 列表分割大小
|
||||
/// </summary>
|
||||
[DeviceProperty("列表分割大小", "默认1千条")]
|
||||
public virtual int SplitSize { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 是否间隔上传
|
||||
/// </summary>
|
||||
[DeviceProperty("是否间隔上传", "False时为变化检测上传")]
|
||||
public virtual bool IsInterval { get; set; } = false;
|
||||
/// <summary>
|
||||
/// 上传间隔时间
|
||||
/// </summary>
|
||||
[DeviceProperty("上传间隔时间", "最小1000ms")]
|
||||
public virtual int UploadInterval { get; set; } = 1000;
|
||||
|
||||
[DeviceProperty("是否选择全部变量", "")] public bool IsAllVariable { get; set; } = false;
|
||||
|
||||
|
||||
}
|
@@ -44,7 +44,7 @@ public class CollectDeviceService : DeviceService<CollectDevice>, ITransient
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
[OperDesc("复制设备与变量")]
|
||||
[OperDesc("复制设备与变量", IsRecordPar = false)]
|
||||
public virtual async Task CopyDevAndVarAsync(IEnumerable<CollectDevice> input)
|
||||
{
|
||||
var variableService = _serviceScope.ServiceProvider.GetService<VariableService>();
|
||||
|
@@ -10,6 +10,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion.DependencyInjection;
|
||||
using Furion.FriendlyException;
|
||||
|
||||
using Mapster;
|
||||
@@ -30,6 +31,7 @@ using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
[Injection(Proxy = typeof(OperDispatchProxy))]
|
||||
public abstract class DeviceService<T> : DbRepository<T> where T : Device, new()
|
||||
{
|
||||
protected readonly IFileService _fileService;
|
||||
|
@@ -267,7 +267,19 @@ public class DriverPluginService : ISingleton
|
||||
}, true);
|
||||
return data;
|
||||
}
|
||||
|
||||
static T GetCustomAttributeRecursive<T>(PropertyInfo property) where T : Attribute
|
||||
{
|
||||
var attribute = property.GetCustomAttribute<T>(false);
|
||||
if (attribute == null && property.DeclaringType.BaseType != null)
|
||||
{
|
||||
var baseProperty = property.DeclaringType.BaseType.GetProperties().FirstOrDefault(p => p.Name == property.Name);
|
||||
if (baseProperty != null)
|
||||
{
|
||||
attribute = GetCustomAttributeRecursive<T>(baseProperty);
|
||||
}
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取插件的属性值
|
||||
/// </summary>
|
||||
@@ -278,7 +290,7 @@ public class DriverPluginService : ISingleton
|
||||
var data = _serviceScope.ServiceProvider.GetService<MemoryCache>().GetOrCreate($"{nameof(GetDriverProperties)}", cacheKey, c =>
|
||||
{
|
||||
var data = driver.DriverPropertys?.GetType().GetProperties().SelectMany(it =>
|
||||
new[] { new { memberInfo = it, attribute = it.GetCustomAttribute<DevicePropertyAttribute>() } })
|
||||
new[] { new { memberInfo = it, attribute = GetCustomAttributeRecursive<DevicePropertyAttribute>(it) } })
|
||||
.Where(x => x.attribute != null).ToList()
|
||||
.SelectMany(it => new[]
|
||||
{
|
||||
@@ -305,7 +317,7 @@ public class DriverPluginService : ISingleton
|
||||
var data = _serviceScope.ServiceProvider.GetService<MemoryCache>().GetOrCreate($"{nameof(GetDriverVariableProperties)}", cacheKey, c =>
|
||||
{
|
||||
var data = driver.VariablePropertys?.GetType().GetProperties()?.SelectMany(it =>
|
||||
new[] { new { memberInfo = it, attribute = it.GetCustomAttribute<VariablePropertyAttribute>() } })
|
||||
new[] { new { memberInfo = it, attribute = GetCustomAttributeRecursive<DevicePropertyAttribute>(it) } })
|
||||
?.Where(x => x.attribute != null).ToList()
|
||||
?.SelectMany(it => new[]
|
||||
{
|
||||
@@ -380,7 +392,7 @@ public class DriverPluginService : ISingleton
|
||||
/// <param name="deviceProperties">插件属性,检索相同名称的属性后写入</param>
|
||||
public void SetDriverProperties(DriverBase driver, List<DependencyProperty> deviceProperties)
|
||||
{
|
||||
var pluginPropertys = driver.DriverPropertys?.GetType().GetProperties().Where(a => a.GetCustomAttribute(typeof(DevicePropertyAttribute)) != null)?.ToList();
|
||||
var pluginPropertys = driver.DriverPropertys?.GetType().GetProperties().Where(a => GetCustomAttributeRecursive<DevicePropertyAttribute>(a) != null)?.ToList();
|
||||
foreach (var propertyInfo in pluginPropertys ?? new())
|
||||
{
|
||||
var deviceProperty = deviceProperties.FirstOrDefault(x => x.PropertyName == propertyInfo.Name);
|
@@ -16,7 +16,7 @@
|
||||
<!--CS-Script与Furion冲突,直接安装覆盖版本-->
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.7.0" />
|
||||
<PackageReference Include="MQTTnet" Version="4.3.1.873" />
|
||||
<PackageReference Include="SqlSugar.TDengineCore" Version="3.2.0" />
|
||||
<PackageReference Include="SqlSugar.TDengineCore" Version="3.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -17,7 +17,7 @@ using System.Text;
|
||||
namespace ThingsGateway.Gateway.Application;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="HistoryValue"/> Master规则
|
||||
/// <see cref="Encoding"/> Master规则
|
||||
/// </summary>
|
||||
public class EncodingMapper : IRegister
|
||||
{
|
||||
|
@@ -74,8 +74,8 @@ public class CollectDeviceWorker : DeviceWorker
|
||||
{
|
||||
var alarmHostService = BackgroundServiceUtil.GetBackgroundService<AlarmWorker>();
|
||||
var uploadDeviceHostService = BackgroundServiceUtil.GetBackgroundService<UploadDeviceWorker>();
|
||||
await alarmHostService.StartAsync();
|
||||
await uploadDeviceHostService.StartAsync();
|
||||
await alarmHostService.StartAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -29,7 +29,7 @@
|
||||
|
||||
@layout MainLayout
|
||||
@using ThingsGateway.Admin.Core;
|
||||
@if (IsMobile)
|
||||
@* @if (IsMobile)
|
||||
{
|
||||
@GetAppDataTable()
|
||||
}
|
||||
@@ -67,7 +67,9 @@ else
|
||||
@GetAppDataTable()
|
||||
</MCol>
|
||||
</MRow>
|
||||
}
|
||||
} *@
|
||||
|
||||
@GetAppDataTable()
|
||||
|
||||
|
||||
<ImportExcel @ref=_importExcel Import="SaveDeviceImportAsync" Preview="DeviceImportAsync" />
|
||||
|
@@ -19,7 +19,7 @@
|
||||
@using Masa.Blazor.Presets;
|
||||
@using System.IO;
|
||||
@using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@using SqlSugar;
|
||||
@using ThingsGateway.Admin.Blazor;
|
||||
@using ThingsGateway.Admin.Core;
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
@if (_tabNumber == 1)
|
||||
{
|
||||
<MRow NoGutters>
|
||||
<MCol Md=2 Cols="12">
|
||||
@* <MCol Md=2 Cols="12">
|
||||
|
||||
<MCard Class="ma-2" Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 80}px );")>
|
||||
<MCardTitle>
|
||||
@@ -73,12 +73,14 @@
|
||||
</LabelContent>
|
||||
</MTreeview>
|
||||
</MCard>
|
||||
</MCol>
|
||||
<MCol Md=3 Cols="12">
|
||||
</MCol> *@
|
||||
<MCol Md=5 Cols="12">
|
||||
<MCard Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight + 80}px; )") Style="overflow-y:auto;" Flat Class="ml-2 my-4">
|
||||
|
||||
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_collectDeviceGroupSearchName"
|
||||
Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.DeviceGroup)) />
|
||||
|
||||
<MVirtualScroll Context="item" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+100}px)") OverscanCount=2 ItemSize="60" Items="_collectDriverBases">
|
||||
<MVirtualScroll Context="item" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+140}px)") OverscanCount=2 ItemSize="60" Items="_collectDriverBases.WhereIF(!_collectDeviceGroupSearchName.IsNullOrEmpty(),a=>a.CurrentDevice.DeviceGroup==_collectDeviceGroupSearchName).ToList()">
|
||||
|
||||
<ItemContent>
|
||||
@if (item.CurrentDevice != null)
|
||||
@@ -250,7 +252,7 @@
|
||||
@if (_tabNumber == 2)
|
||||
{
|
||||
<MRow>
|
||||
<MCol Md=2 Cols="12">
|
||||
@* <MCol Md=2 Cols="12">
|
||||
<MCard Class="ma-2" Style=@($"height: calc(100vh - {BlazorResourceConst.DefaultHeight + 80}px); )")>
|
||||
<MCardTitle>
|
||||
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_uploadDeviceGroupSearchName"
|
||||
@@ -274,11 +276,13 @@
|
||||
</LabelContent>
|
||||
</MTreeview>
|
||||
</MCard>
|
||||
</MCol>
|
||||
<MCol Md=3 Cols="12">
|
||||
</MCol> *@
|
||||
<MCol Md=5 Cols="12">
|
||||
<MCard Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+80}px)") Style="overflow-y:auto;" Flat Class="ml-2 my-4">
|
||||
<MTextField Dense Style="max-width:200px;" HideDetails=@("auto") Class="mx-2 my-1" @bind-Value="_uploadDeviceGroupSearchName"
|
||||
Outlined Label=@typeof(CollectDevice).GetDescription(nameof(CollectDevice.DeviceGroup)) />
|
||||
|
||||
<MVirtualScroll Context="item" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+100}px)") OverscanCount=2 ItemSize="60" Items="_uploadDriverBases">
|
||||
<MVirtualScroll Context="item" Height=@($"calc(100vh - {BlazorResourceConst.DefaultHeight+140}px)") OverscanCount=2 ItemSize="60" Items="_uploadDriverBases.WhereIF(!_uploadDeviceGroupSearchName.IsNullOrEmpty(),a=>a.CurrentDevice.DeviceGroup==_uploadDeviceGroupSearchName).ToList()">
|
||||
|
||||
<ItemContent>
|
||||
@if (item.CurrentDevice != null)
|
||||
|
@@ -30,7 +30,7 @@
|
||||
@inject UserResoures UserResoures
|
||||
@layout MainLayout
|
||||
|
||||
@if (IsMobile)
|
||||
@* @if (IsMobile)
|
||||
{
|
||||
@GetAppDataTable()
|
||||
|
||||
@@ -69,7 +69,8 @@ else
|
||||
|
||||
</MCol>
|
||||
</MRow>
|
||||
}
|
||||
} *@
|
||||
@GetAppDataTable()
|
||||
|
||||
<ImportExcel @ref=_importExcel Import="SaveDeviceImportAsync" Preview="DeviceImportAsync" />
|
||||
|
||||
|
@@ -30,7 +30,7 @@
|
||||
@inherits BaseComponentBase
|
||||
@inject UserResoures UserResoures
|
||||
@layout MainLayout
|
||||
@if (IsMobile)
|
||||
@* @if (IsMobile)
|
||||
{
|
||||
@GetAppDataTable()
|
||||
|
||||
@@ -69,7 +69,11 @@ else
|
||||
@GetAppDataTable()
|
||||
</MCol>
|
||||
</MRow>
|
||||
}
|
||||
} *@
|
||||
|
||||
@GetAppDataTable()
|
||||
|
||||
|
||||
@code {
|
||||
RenderFragment GetAppDataTable()
|
||||
{
|
||||
|
@@ -29,7 +29,7 @@
|
||||
|
||||
@layout MainLayout
|
||||
@using ThingsGateway.Admin.Core;
|
||||
@if (IsMobile)
|
||||
@* @if (IsMobile)
|
||||
{
|
||||
@GetAppDataTable()
|
||||
}
|
||||
@@ -67,8 +67,9 @@ else
|
||||
@GetAppDataTable()
|
||||
</MCol>
|
||||
</MRow>
|
||||
}
|
||||
} *@
|
||||
|
||||
@GetAppDataTable()
|
||||
|
||||
<ImportExcel @ref=_importExcel Import="SaveDeviceImportAsync" Preview="DeviceImportAsync" />
|
||||
|
||||
|
@@ -12,10 +12,8 @@
|
||||
|
||||
namespace ThingsGateway.Gateway.Core;
|
||||
/// <summary>
|
||||
/// 历史报警表
|
||||
/// 报警变量
|
||||
/// </summary>
|
||||
[IgnoreSqlTable]
|
||||
[SugarTable("historyAlarm", TableDescription = "历史报警表")]
|
||||
public class AlarmVariable : PrimaryIdEntity
|
||||
{
|
||||
/// <inheritdoc cref="DeviceVariable.Name"/>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>4.0.0.0</Version>
|
||||
<Version>4.0.0.3</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
|
||||
|
@@ -29,7 +29,7 @@ namespace ThingsGateway.Plugin.Kafka;
|
||||
/// <summary>
|
||||
/// Kafka消息生产
|
||||
/// </summary>
|
||||
public partial class KafkaProducer : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public partial class KafkaProducer : UpLoadBaseWithCacheT<DeviceData, VariableData>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
@@ -41,7 +41,7 @@ public partial class KafkaProducer : UpLoadBaseWithCache<DeviceData, VariableDat
|
||||
|
||||
protected override IReadWrite _readWrite => null;
|
||||
|
||||
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
|
||||
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
@@ -19,7 +19,7 @@ namespace ThingsGateway.Plugin.Kafka;
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public partial class KafkaProducer : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public partial class KafkaProducer : UpLoadBaseWithCacheT<DeviceData, VariableData>
|
||||
{
|
||||
private const string devType = "dev";
|
||||
private const string varType = "var";
|
||||
|
@@ -15,7 +15,7 @@ namespace ThingsGateway.Plugin.Kafka;
|
||||
/// <summary>
|
||||
/// kafka 生产者属性
|
||||
/// </summary>
|
||||
public class KafkaProducerProperty : UploadPropertyWithCache
|
||||
public class KafkaProducerProperty : UploadPropertyWithCacheT
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务地址
|
||||
|
@@ -78,6 +78,7 @@ public class ModbusSerialServer : UpLoadBase
|
||||
DataFormat = _driverPropertys.DataFormat,
|
||||
Station = _driverPropertys.Station,
|
||||
CacheTimeout = _driverPropertys.CacheTimeout,
|
||||
WriteMemory = _driverPropertys.WriteMemory,
|
||||
MulStation = _driverPropertys.MulStation
|
||||
};
|
||||
|
||||
|
@@ -67,6 +67,11 @@ public class ModbusSerialServerProperty : DriverPropertyBase
|
||||
[DeviceProperty("允许写入", "")]
|
||||
public bool DeviceRpcEnable { get; set; }
|
||||
/// <summary>
|
||||
/// 立即写入内存
|
||||
/// </summary>
|
||||
[DeviceProperty("立即写入内存", "")]
|
||||
public bool WriteMemory { get; set; }
|
||||
/// <summary>
|
||||
/// 组包缓存超时ms
|
||||
/// </summary>
|
||||
[DeviceProperty("组包缓存超时", "某些设备性能较弱,报文间需要间隔较长时间,可以设置更长的组包缓存,默认1000ms")]
|
||||
|
@@ -64,6 +64,7 @@ public class ModbusTcpServer : UpLoadBase
|
||||
iPHost = new IPHost($"{_driverPropertys.IP}:{_driverPropertys.Port}");
|
||||
}
|
||||
FoundataionConfig.SetListenIPHosts(new IPHost[] { iPHost });
|
||||
FoundataionConfig.SetMaxCount(30000);
|
||||
var service = new TcpService();
|
||||
service.Setup(FoundataionConfig);
|
||||
//载入配置
|
||||
@@ -72,6 +73,7 @@ public class ModbusTcpServer : UpLoadBase
|
||||
DataFormat = _driverPropertys.DataFormat,
|
||||
Station = _driverPropertys.Station,
|
||||
CacheTimeout = _driverPropertys.CacheTimeout,
|
||||
WriteMemory = _driverPropertys.WriteMemory,
|
||||
MulStation = _driverPropertys.MulStation
|
||||
};
|
||||
|
||||
|
@@ -48,6 +48,11 @@ public class ModbusTcpServerProperty : DriverPropertyBase
|
||||
[DeviceProperty("允许写入", "")]
|
||||
public bool DeviceRpcEnable { get; set; }
|
||||
/// <summary>
|
||||
/// 立即写入内存
|
||||
/// </summary>
|
||||
[DeviceProperty("立即写入内存", "")]
|
||||
public bool WriteMemory { get; set; }
|
||||
/// <summary>
|
||||
/// 组包缓存超时ms
|
||||
/// </summary>
|
||||
[DeviceProperty("组包缓存超时", "某些设备性能较弱,报文间需要间隔较长时间,可以设置更长的组包缓存,默认1000ms")]
|
||||
|
@@ -24,7 +24,7 @@ namespace ThingsGateway.Plugin.Mqtt;
|
||||
/// <summary>
|
||||
/// IotSharpClient
|
||||
/// </summary>
|
||||
public partial class IotSharpClient : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public partial class IotSharpClient : UpLoadBaseWithCacheT<DeviceData, VariableData>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
@@ -35,7 +35,7 @@ public partial class IotSharpClient : UpLoadBaseWithCache<DeviceData, VariableDa
|
||||
public override VariablePropertyBase VariablePropertys => _variablePropertys;
|
||||
protected override IReadWrite _readWrite => null;
|
||||
|
||||
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
|
||||
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
|
@@ -27,7 +27,7 @@ namespace ThingsGateway.Plugin.Mqtt;
|
||||
/// <summary>
|
||||
/// IotSharpClient
|
||||
/// </summary>
|
||||
public partial class IotSharpClient : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public partial class IotSharpClient : UpLoadBaseWithCacheT<DeviceData, VariableData>
|
||||
{
|
||||
/// <summary>
|
||||
/// rpcmethodname存疑,定为自定义方法,在ThingsGateway上写入变量的方法固定为"Write"
|
||||
|
@@ -15,7 +15,7 @@ namespace ThingsGateway.Plugin.Mqtt;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class IotSharpClientProperty : UploadPropertyWithCache
|
||||
public class IotSharpClientProperty : UploadPropertyWithCacheT
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
|
@@ -26,7 +26,7 @@ namespace ThingsGateway.Plugin.Mqtt;
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public partial class MqttClient : UpLoadBaseWithCacheT<DeviceData, VariableData>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
@@ -37,7 +37,7 @@ public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public override VariablePropertyBase VariablePropertys => _variablePropertys;
|
||||
protected override IReadWrite _readWrite => null;
|
||||
|
||||
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
|
||||
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@@ -69,14 +69,20 @@ public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
{
|
||||
base.Init(client);
|
||||
var mqttFactory = new MqttFactory();
|
||||
_mqttClientOptions = mqttFactory.CreateClientOptionsBuilder()
|
||||
var mqttClientOptionsBuilder = mqttFactory.CreateClientOptionsBuilder()
|
||||
.WithClientId(_driverPropertys.ConnectId)
|
||||
.WithCredentials(_driverPropertys.UserName, _driverPropertys.Password)//账密
|
||||
.WithTcpServer(_driverPropertys.IP, _driverPropertys.Port)//服务器
|
||||
|
||||
.WithCleanSession(true)
|
||||
.WithKeepAlivePeriod(TimeSpan.FromSeconds(120.0))
|
||||
.WithoutThrowOnNonSuccessfulConnectResponse()
|
||||
.WithoutThrowOnNonSuccessfulConnectResponse();
|
||||
if (_driverPropertys.IsWebSocket)
|
||||
_mqttClientOptions = mqttClientOptionsBuilder.WithWebSocketServer(a => a.WithUri(_driverPropertys.WebSocktUrl))
|
||||
.Build();
|
||||
else
|
||||
_mqttClientOptions = mqttClientOptionsBuilder.WithTcpServer(_driverPropertys.IP, _driverPropertys.Port)//服务器
|
||||
.Build();
|
||||
|
||||
_mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
|
||||
.WithTopicFilter(
|
||||
f =>
|
||||
|
@@ -32,7 +32,7 @@ namespace ThingsGateway.Plugin.Mqtt;
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public partial class MqttClient : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public partial class MqttClient : UpLoadBaseWithCacheT<DeviceData, VariableData>
|
||||
{
|
||||
private const string devType = "dev";
|
||||
private const string varType = "var";
|
||||
|
@@ -15,7 +15,7 @@ namespace ThingsGateway.Plugin.Mqtt;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class MqttClientProperty : UploadPropertyWithCache
|
||||
public class MqttClientProperty : UploadPropertyWithCacheT
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
@@ -29,6 +29,16 @@ public class MqttClientProperty : UploadPropertyWithCache
|
||||
[DeviceProperty("端口", "")]
|
||||
public override int Port { get; set; } = 1883;
|
||||
/// <summary>
|
||||
/// 是否websocket连接
|
||||
/// </summary>
|
||||
[DeviceProperty("是否WebSocket连接", "true=>websocket,flase=>tcp")]
|
||||
public bool IsWebSocket { get; set; } = false;
|
||||
/// <summary>
|
||||
/// WebSocktUrl
|
||||
/// </summary>
|
||||
[DeviceProperty("WebSocktUrl", "")]
|
||||
public string WebSocktUrl { get; set; } = "ws://127.0.0.1:8083/mqtt";
|
||||
/// <summary>
|
||||
/// 账号
|
||||
/// </summary>
|
||||
[DeviceProperty("账号", "")]
|
||||
|
@@ -14,15 +14,18 @@ using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MQTTnet;
|
||||
using MQTTnet.AspNetCore;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Protocol;
|
||||
using MQTTnet.Server;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
using ThingsGateway.Admin.Application;
|
||||
@@ -93,6 +96,7 @@ public class MqttServer : UpLoadBase
|
||||
_mqttServer.InterceptingSubscriptionAsync -= MqttServer_InterceptingSubscriptionAsync; ;
|
||||
_mqttServer?.SafeDispose();
|
||||
}
|
||||
_webHost?.Dispose();
|
||||
_globalDeviceData?.AllVariables?.ForEach(a => a.VariableValueChange -= VariableValueChange);
|
||||
_globalDeviceData?.CollectDevices?.ForEach(a =>
|
||||
{
|
||||
@@ -102,16 +106,32 @@ public class MqttServer : UpLoadBase
|
||||
_collectVariableRunTimes.Clear();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private IWebHost _webHost { get; set; }
|
||||
protected override void Init(ISenderClient client = null)
|
||||
{
|
||||
var mqttFactory = new MqttFactory();
|
||||
var mqttServerOptions = mqttFactory.CreateServerOptionsBuilder()
|
||||
.WithDefaultEndpointBoundIPAddress(string.IsNullOrEmpty(_driverPropertys.IP) ? null : IPAddress.Parse(_driverPropertys.IP))
|
||||
.WithDefaultEndpointPort(_driverPropertys.Port)
|
||||
.WithDefaultEndpoint()
|
||||
.Build();
|
||||
_mqttServer = mqttFactory.CreateMqttServer(mqttServerOptions);
|
||||
//var mqttFactory = new MqttFactory();
|
||||
//var mqttServerOptions = mqttFactory.CreateServerOptionsBuilder()
|
||||
// .WithDefaultEndpointBoundIPAddress(string.IsNullOrEmpty(_driverPropertys.IP) ? null : IPAddress.Parse(_driverPropertys.IP))
|
||||
// .WithDefaultEndpointPort(_driverPropertys.Port)
|
||||
// .WithDefaultEndpoint()
|
||||
// .Build();
|
||||
//_mqttServer = mqttFactory.CreateMqttServer(mqttServerOptions);
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory)
|
||||
.Build();
|
||||
var webBuilder = new WebHostBuilder()
|
||||
.UseKestrel(
|
||||
o =>
|
||||
{
|
||||
o.ListenAnyIP(_driverPropertys.Port, l => l.UseMqtt());
|
||||
o.ListenAnyIP(_driverPropertys.WebSocketPort);
|
||||
});
|
||||
webBuilder.UseStartup<MqttServerStartup>();
|
||||
_webHost = webBuilder.UseConfiguration(configuration)
|
||||
.Build();
|
||||
|
||||
|
||||
_mqttServer = _webHost.Services.GetService<MqttHostedServer>();
|
||||
|
||||
CollectDevices.Where(a => CurrentDevice.DeviceVariableRunTimes.Select(b => b.DeviceId).Contains(a.Id)).ForEach(a =>
|
||||
{
|
||||
@@ -121,11 +141,11 @@ public class MqttServer : UpLoadBase
|
||||
{
|
||||
a.VariableValueChange += VariableValueChange;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected override async Task ProtectedBeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_ = _webHost.StartAsync(cancellationToken);
|
||||
if (_mqttServer != null)
|
||||
{
|
||||
_mqttServer.ValidatingConnectionAsync += MqttServer_ValidatingConnectionAsync;
|
||||
|
@@ -17,17 +17,18 @@ namespace ThingsGateway.Plugin.Mqtt;
|
||||
public class MqttServerProperty : DriverPropertyBase
|
||||
{
|
||||
[DeviceProperty("是否选择全部变量", "")] public bool IsAllVariable { get; set; } = false;
|
||||
/// <summary>
|
||||
/// IP
|
||||
/// </summary>
|
||||
[DeviceProperty("IP", "留空则全部监听")]
|
||||
public override string IP { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
[DeviceProperty("端口", "")]
|
||||
public override int Port { get; set; } = 1883;
|
||||
/// <summary>
|
||||
/// WebSocket端口
|
||||
/// </summary>
|
||||
[DeviceProperty("WebSocket端口", "")]
|
||||
public int WebSocketPort { get; set; } = 8083;
|
||||
/// <summary>
|
||||
/// 允许连接的ID(前缀)
|
||||
/// </summary>
|
||||
[DeviceProperty("允许连接的ID(前缀)", "")]
|
||||
|
@@ -0,0 +1,63 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using MQTTnet.AspNetCore;
|
||||
using MQTTnet.Diagnostics;
|
||||
|
||||
namespace MQTTnet.Server;
|
||||
/// <summary>
|
||||
/// MqttServerStartup
|
||||
/// </summary>
|
||||
public class MqttServerStartup
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton(s =>
|
||||
{
|
||||
var serverOptionsBuilder = new MqttServerOptionsBuilder();
|
||||
|
||||
serverOptionsBuilder.WithDefaultEndpoint();
|
||||
|
||||
return serverOptionsBuilder.Build();
|
||||
});
|
||||
|
||||
var logger = new MqttNetEventLogger();
|
||||
services.AddSingleton<IMqttNetLogger>(logger);
|
||||
services.AddSingleton<MqttHostedServer>();
|
||||
//services.AddSingleton<IHostedService>(s => s.GetService<MqttHostedServer>());
|
||||
////不再注册HostService,MqttServer的生命周期由插件完成
|
||||
services.AddSingleton<MqttServer>(s => s.GetService<MqttHostedServer>());
|
||||
services.AddMqttConnectionHandler();
|
||||
services.AddConnections();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapConnectionHandler<MqttConnectionHandler>(
|
||||
"/mqtt",
|
||||
httpConnectionDispatcherOptions => httpConnectionDispatcherOptions.WebSockets.SubProtocolSelector =
|
||||
protocolList => protocolList.FirstOrDefault() ?? string.Empty);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -3,10 +3,14 @@
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
||||
<Exec Command=" set dir="$(SolutionDir)web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)"
 if not exist %25dir%25 md %25dir%25 
copy "$(TargetDir)*Mqtt*.dll" %25dir%25


" />
|
||||
<Exec Command=" set dir="$(SolutionDir)web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)"
 if not exist %25dir%25 md %25dir%25 
copy "$(TargetDir)*Mqtt*.dll" %25dir%25

copy "$(TargetDir)*MQTTnet.AspNetCore*.dll" %25dir%25
" />
|
||||
|
||||
</Target>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MQTTnet.AspNetCore" Version="4.3.1.873" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
@@ -28,7 +28,7 @@ namespace ThingsGateway.Plugin.QuestDB;
|
||||
/// <summary>
|
||||
/// SQLDB
|
||||
/// </summary>
|
||||
public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryValue>
|
||||
public partial class QuestDB : UpLoadBaseWithCacheT<DeviceData, QuestDBHistoryValue>
|
||||
{
|
||||
protected override bool _device => false;
|
||||
protected override bool _variable => true;
|
||||
@@ -41,7 +41,7 @@ public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryVal
|
||||
public override VariablePropertyBase VariablePropertys => _variablePropertys;
|
||||
protected override IReadWrite _readWrite => null;
|
||||
|
||||
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
|
||||
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@@ -59,7 +59,7 @@ public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryVal
|
||||
{
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<DeviceVariableRunTime, QuestDBHistoryValue>()
|
||||
.Map(dest => dest.Value, (src) => ValueReturn(src))
|
||||
.Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty)
|
||||
.Map(dest => dest.CollectTime, (src) => src.CollectTime < DateTime.MinValue ? DateTime.MinValue.ToUniversalTime() : src.CollectTime.ToUniversalTime())//注意sqlsugar插入时无时区,直接utc时间
|
||||
.Map(dest => dest.CreateTime, (src) => DateTime.UtcNow)
|
||||
;//注意sqlsugar插入时无时区,直接utc时间
|
||||
|
@@ -57,5 +57,5 @@ public class QuestDBHistoryValue
|
||||
/// 变量值
|
||||
/// </summary>
|
||||
[Description("变量值")]
|
||||
public double Value { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
@@ -22,7 +22,6 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
@@ -31,7 +30,7 @@ namespace ThingsGateway.Plugin.QuestDB;
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryValue>
|
||||
public partial class QuestDB : UpLoadBaseWithCacheT<DeviceData, QuestDBHistoryValue>
|
||||
{
|
||||
private const string devType = "dev";
|
||||
private const string varType = "var";
|
||||
@@ -39,18 +38,6 @@ public partial class QuestDB : UpLoadBaseWithCache<DeviceData, QuestDBHistoryVal
|
||||
private readonly QuestDBVariableProperty _variablePropertys = new();
|
||||
|
||||
private volatile bool success = true;
|
||||
private static object ValueReturn(DeviceVariableRunTime src)
|
||||
{
|
||||
var data = src.Value?.ToString()?.ToBool();
|
||||
if (data != null)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return src.Value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void AddCache(List<CacheItem> cacheItems, IEnumerable<QuestDBHistoryValue> dev)
|
||||
{
|
||||
|
@@ -17,7 +17,7 @@ namespace ThingsGateway.Plugin.QuestDB;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class QuestDBProperty : UploadPropertyWithCache
|
||||
public class QuestDBProperty : UploadPropertyWithCacheT
|
||||
{
|
||||
|
||||
public DbType DbType { get; set; } = DbType.QuestDB;
|
||||
|
@@ -27,7 +27,7 @@ namespace ThingsGateway.Plugin.RabbitMQ;
|
||||
/// <summary>
|
||||
/// Kafka消息生产
|
||||
/// </summary>
|
||||
public partial class RabbitMQProducer : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public partial class RabbitMQProducer : UpLoadBaseWithCacheT<DeviceData, VariableData>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
@@ -39,7 +39,7 @@ public partial class RabbitMQProducer : UpLoadBaseWithCache<DeviceData, Variable
|
||||
|
||||
protected override IReadWrite _readWrite => null;
|
||||
|
||||
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
|
||||
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
@@ -21,7 +21,7 @@ namespace ThingsGateway.Plugin.RabbitMQ;
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public partial class RabbitMQProducer : UpLoadBaseWithCache<DeviceData, VariableData>
|
||||
public partial class RabbitMQProducer : UpLoadBaseWithCacheT<DeviceData, VariableData>
|
||||
{
|
||||
private const string devType = "dev";
|
||||
private const string varType = "var";
|
||||
|
@@ -17,7 +17,7 @@ namespace ThingsGateway.Plugin.RabbitMQ;
|
||||
/// <summary>
|
||||
/// kafka 生产者属性
|
||||
/// </summary>
|
||||
public class RabbitMQProducerProperty : UploadPropertyWithCache
|
||||
public class RabbitMQProducerProperty : UploadPropertyWithCacheT
|
||||
{
|
||||
/// <summary>
|
||||
/// IP
|
||||
|
@@ -28,7 +28,7 @@ namespace ThingsGateway.Plugin.SQLDB;
|
||||
/// <summary>
|
||||
/// SQLDB
|
||||
/// </summary>
|
||||
public partial class SQLDB : UpLoadBaseWithCache<DeviceData, SQLHistoryValue>
|
||||
public partial class SQLDB : UpLoadBaseWithCacheT<DeviceData, SQLHistoryValue>
|
||||
{
|
||||
protected override bool _device => false;
|
||||
protected override bool _variable => _driverPropertys.IsHisDB;
|
||||
@@ -41,7 +41,7 @@ public partial class SQLDB : UpLoadBaseWithCache<DeviceData, SQLHistoryValue>
|
||||
public override VariablePropertyBase VariablePropertys => _variablePropertys;
|
||||
protected override IReadWrite _readWrite => null;
|
||||
|
||||
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
|
||||
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
|
@@ -30,7 +30,7 @@ namespace ThingsGateway.Plugin.SQLDB;
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public partial class SQLDB : UpLoadBaseWithCache<DeviceData, SQLHistoryValue>
|
||||
public partial class SQLDB : UpLoadBaseWithCacheT<DeviceData, SQLHistoryValue>
|
||||
{
|
||||
private const string devType = "dev";
|
||||
private const string varType = "var";
|
||||
|
@@ -17,7 +17,7 @@ namespace ThingsGateway.Plugin.SQLDB;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class SQLDBProperty : UploadPropertyWithCache
|
||||
public class SQLDBProperty : UploadPropertyWithCacheT
|
||||
{
|
||||
[DeviceProperty("是否实时表", "true=>实时表更新")] public bool IsReadDB { get; set; } = false;
|
||||
[DeviceProperty("是否历史表", "true=>历史存储(按月分表)")] public bool IsHisDB { get; set; } = true;
|
||||
|
@@ -0,0 +1,15 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
global using ThingsGateway.Foundation.Core;
|
||||
global using ThingsGateway.Gateway.Application;
|
||||
global using ThingsGateway.Gateway.Core;
|
@@ -0,0 +1,9 @@
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLHisAlarm;
|
||||
|
||||
|
||||
[SugarTable("historyAlarm", TableDescription = "历史报警表")]
|
||||
internal class HistoryAlarm : AlarmVariable
|
||||
{
|
||||
}
|
@@ -0,0 +1,180 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using LiteDB;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using MQTTnet.Diagnostics;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Sockets;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLHisAlarm;
|
||||
|
||||
/// <summary>
|
||||
/// SQLDB
|
||||
/// </summary>
|
||||
public partial class SQLHisAlarm : UpLoadBaseWithCache
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Type DriverDebugUIType => null;
|
||||
|
||||
public override Type DriverUIType => null;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override VariablePropertyBase VariablePropertys => null;
|
||||
protected override IReadWrite _readWrite => null;
|
||||
|
||||
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
|
||||
public override void Init(DeviceRunTime device)
|
||||
{
|
||||
base.Init(device);
|
||||
device.DeviceVariableRunTimes = _globalDeviceData.AllVariables.Where(a => a.AlarmEnable).ToList();
|
||||
CollectDevices = _globalDeviceData.CollectDevices.Where(a => a.DeviceVariableRunTimes.Any(a => a.AlarmEnable)).ToList();
|
||||
}
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool IsConnected() => success;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $" {nameof(SQLHisAlarm)}";
|
||||
}
|
||||
private TypeAdapterConfig _config;
|
||||
protected override void Init(ISenderClient client = null)
|
||||
{
|
||||
base.Init(client);
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<AlarmVariable, HistoryAlarm>()
|
||||
.Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty)
|
||||
.Map(dest => dest.Id, (src) =>
|
||||
YitIdHelper.NextId());
|
||||
var alarmWorker = BackgroundServiceUtil.GetBackgroundService<AlarmWorker>();
|
||||
alarmWorker.OnAlarmChanged += AlarmWorker_OnAlarmChanged;
|
||||
|
||||
if (_uploadPropertyWithCache.CycleInterval <= 100) _uploadPropertyWithCache.CycleInterval = 100;
|
||||
}
|
||||
|
||||
private void AlarmWorker_OnAlarmChanged(AlarmVariable alarmVariable)
|
||||
{
|
||||
if (!CurrentDevice.KeepRun)
|
||||
return;
|
||||
AddVariableQueue(alarmVariable.Adapt<HistoryAlarm>(_config ?? TypeAdapterConfig.GlobalSettings));
|
||||
}
|
||||
|
||||
protected override async Task ProtectedBeforStartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var db = GetDb();
|
||||
db.CodeFirst.InitTables(typeof(HistoryAlarm));
|
||||
await base.ProtectedBeforStartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
protected override async Task ProtectedExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
//获取设备连接状态
|
||||
if (IsConnected())
|
||||
{
|
||||
//更新设备活动时间
|
||||
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (!IsUploadBase)
|
||||
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, 999);
|
||||
}
|
||||
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, CurrentDevice.ErrorCount + 1);
|
||||
|
||||
var cacheItems = new List<CacheItem>();
|
||||
var db = GetDb();
|
||||
db.Ado.CancellationToken = cancellationToken;
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
var list = _alarmVariables.ToListWithDequeue();
|
||||
if (list?.Count != 0)
|
||||
{
|
||||
var result = await InserableAsync(db, list, cancellationToken);
|
||||
if (success != result.IsSuccess)
|
||||
{
|
||||
if (!result.IsSuccess)
|
||||
LogMessage.Warning(result.ToString());
|
||||
success = result.IsSuccess;
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
AddCache(cacheItems, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (cacheItems.Count > 0)
|
||||
CacheDb.Cache.Insert(cacheItems);
|
||||
|
||||
List<long> successIds = new();
|
||||
try
|
||||
{
|
||||
var varList = CacheDb.Cache.Find(a => a.Type == varType, 0, _driverPropertys.CacheSendCount).ToList();//最大100w条
|
||||
{
|
||||
var item = varList.SelectMany(a => a.Value.FromJsonString<List<HistoryAlarm>>()).ToList();
|
||||
if (item.Count != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
|
||||
var result = await InserableAsync(db, item, cancellationToken);
|
||||
if (success != result.IsSuccess)
|
||||
{
|
||||
if (!result.IsSuccess)
|
||||
LogMessage.Warning(result.ToString());
|
||||
success = result.IsSuccess;
|
||||
}
|
||||
if (result.IsSuccess)
|
||||
successIds.AddRange(varList.Select(a => a.Id));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage?.LogWarning(ex);
|
||||
}
|
||||
|
||||
if (successIds.Count > 0)
|
||||
CacheDb.Cache.DeleteMany(a => successIds.Contains(a.Id));
|
||||
}
|
||||
|
||||
await Delay(_driverPropertys.CycleInterval, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,222 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using Furion;
|
||||
|
||||
using Mapster;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLHisAlarm;
|
||||
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public partial class SQLHisAlarm : UpLoadBaseWithCache
|
||||
{
|
||||
private const string devType = "dev";
|
||||
private const string varType = "var";
|
||||
private readonly SQLHisAlarmProperty _driverPropertys = new();
|
||||
//private readonly SQLHisAlarmVariableProperty _variablePropertys = new();
|
||||
private readonly EasyLock easyLock = new();
|
||||
|
||||
private ConcurrentQueue<HistoryAlarm> _alarmVariables = new();
|
||||
private volatile bool success = true;
|
||||
|
||||
/// <summary>
|
||||
/// Aop设置
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
private static void AopSetting(SqlSugarClient db)
|
||||
{
|
||||
var config = db.CurrentConnectionConfig;
|
||||
|
||||
// 设置超时时间
|
||||
db.Ado.CommandTimeOut = 30;
|
||||
|
||||
// 打印SQL语句
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
//如果是开发环境就打印sql
|
||||
if (App.HostEnvironment.IsDevelopment())
|
||||
{
|
||||
//if (sql.StartsWith("SELECT"))
|
||||
//{
|
||||
// Console.ForegroundColor = ConsoleColor.Green;
|
||||
//}
|
||||
//if (sql.StartsWith("UPDATE"))
|
||||
//{
|
||||
// Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
//}
|
||||
//if (sql.StartsWith("INSERT"))
|
||||
//{
|
||||
// Console.ForegroundColor = ConsoleColor.Blue;
|
||||
//}
|
||||
//if (sql.StartsWith("DELETE"))
|
||||
//{
|
||||
// Console.ForegroundColor = ConsoleColor.Red;
|
||||
//}
|
||||
//WriteSqlLog(UtilMethods.GetSqlString(config.DbType, sql, pars));
|
||||
//Console.ForegroundColor = ConsoleColor.White;
|
||||
//Console.WriteLine();
|
||||
}
|
||||
};
|
||||
//异常
|
||||
db.Aop.OnError = (ex) =>
|
||||
{
|
||||
//如果是开发环境就打印日志
|
||||
if (App.WebHostEnvironment.IsDevelopment())
|
||||
{
|
||||
if (ex.Parametres == null) return;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
|
||||
WriteSqlLogError(UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres));
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static void WriteSqlLog(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
|
||||
private static void WriteSqlLogError(string msg)
|
||||
{
|
||||
Console.WriteLine("【Sql执行错误时间】:" + DateTimeExtensions.CurrentDateTime.ToDefaultDateTimeFormat());
|
||||
Console.WriteLine("【Sql语句】:" + msg + Environment.NewLine);
|
||||
}
|
||||
|
||||
private void AddCache(List<CacheItem> cacheItems, IEnumerable<HistoryAlarm> dev)
|
||||
{
|
||||
var data = dev.ChunkBetter(_driverPropertys.CacheItemCount);
|
||||
foreach (var item in data)
|
||||
{
|
||||
var cacheItem = new CacheItem()
|
||||
{
|
||||
Id = YitIdHelper.NextId(),
|
||||
Type = varType,
|
||||
Value = item.ToJsonString(),
|
||||
};
|
||||
cacheItems.Add(cacheItem);
|
||||
}
|
||||
}
|
||||
private void AddCache(IEnumerable<IEnumerable<HistoryAlarm>> devData, List<CacheItem> cacheItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var dev in devData)
|
||||
{
|
||||
AddCache(cacheItems, dev);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage.LogWarning(ex, "缓存失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加变量队列,超限后会入缓存
|
||||
/// </summary>
|
||||
/// <param name="variableData"></param>
|
||||
private void AddVariableQueue(HistoryAlarm variableData)
|
||||
{
|
||||
//检测队列长度,超限存入缓存数据库
|
||||
if (_alarmVariables.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
List<HistoryAlarm> list = null;
|
||||
lock (_alarmVariables)
|
||||
{
|
||||
if (_alarmVariables.Count > _uploadPropertyWithCache.QueueMaxCount)
|
||||
{
|
||||
list = _alarmVariables.ToListWithDequeue();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (list != null)
|
||||
{
|
||||
var devData = list.ChunkBetter(_uploadPropertyWithCache.SplitSize);
|
||||
var cacheItems = new List<CacheItem>();
|
||||
AddCache(devData, cacheItems);
|
||||
|
||||
if (cacheItems.Count > 0)
|
||||
CacheDb.Cache.Insert(cacheItems);
|
||||
}
|
||||
}
|
||||
|
||||
_alarmVariables.Enqueue(variableData);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private SqlSugarClient GetDb()
|
||||
{
|
||||
var configureExternalServices = new ConfigureExternalServices
|
||||
{
|
||||
EntityService = (type, column) => // 修改列可空-1、带?问号 2、String类型若没有Required
|
||||
{
|
||||
if ((type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
|| (type.PropertyType == typeof(string) && type.GetCustomAttribute<RequiredAttribute>() == null))
|
||||
column.IsNullable = true;
|
||||
},
|
||||
};
|
||||
var sqlSugarClient = new SqlSugarClient(new ConnectionConfig()
|
||||
{
|
||||
ConnectionString = _driverPropertys.BigTextConnectStr,//连接字符串
|
||||
DbType = _driverPropertys.DbType,//数据库类型
|
||||
IsAutoCloseConnection = true, //不设成true要手动close
|
||||
ConfigureExternalServices = configureExternalServices,
|
||||
}
|
||||
);
|
||||
AopSetting(sqlSugarClient);//aop配置
|
||||
return sqlSugarClient;
|
||||
}
|
||||
private async Task<OperResult> InserableAsync(SqlSugarClient db, List<HistoryAlarm> dbInserts, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
//.SplitTable()
|
||||
var result = await db.Fastest<HistoryAlarm>().PageSize(50000).BulkCopyAsync(dbInserts);
|
||||
//var result = await db.Insertable(dbInserts).SplitTable().ExecuteCommandAsync();
|
||||
if (result > 0)
|
||||
{
|
||||
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, 0);
|
||||
LogMessage.Trace($"{FoundationConst.LogMessageHeader}主题:{nameof(HistoryAlarm)}");
|
||||
}
|
||||
return OperResult.CreateSuccessResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CurrentDevice.SetDeviceStatus(DateTimeExtensions.CurrentDateTime, 999);
|
||||
return new(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using SqlSugar;
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLHisAlarm;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class SQLHisAlarmProperty : UploadPropertyWithCache
|
||||
{
|
||||
[DeviceProperty("数据库类型", "MySql/SqlServer")] public DbType DbType { get; set; } = DbType.MySql;
|
||||
[DeviceProperty("链接字符串", "")] public string BigTextConnectStr { get; set; } = "server=localhost;Database=test;Uid=root;Pwd=111111;AllowLoadLocalInfile=true;";
|
||||
public override bool IsAllVariable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 每次发送时合并的缓存值数量
|
||||
/// </summary>
|
||||
public virtual int CacheSendCount { get; set; } = 500;
|
||||
/// <summary>
|
||||
/// 每次添加缓存时,合并的变量值数量
|
||||
/// </summary>
|
||||
public virtual int CacheItemCount { get; set; } = 2000;
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
#region copyright
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||||
// 使用文档:https://diego2098.gitee.io/thingsgateway-docs/
|
||||
// QQ群:605534569
|
||||
//------------------------------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace ThingsGateway.Plugin.SQLHisAlarm;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
//public class SQLHisAlarmVariableProperty : VariablePropertyBase
|
||||
//{
|
||||
|
||||
//}
|
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
||||
<Exec Command=" set dir="$(SolutionDir)Web\ThingsGateway.Web.Entry\bin\$(Configuration)\$(TargetFramework)\Plugins\$(AssemblyName)"
 if not exist %25dir%25 md %25dir%25 
copy "$(TargetDir)*SQLHisAlarm*.dll" %25dir%25



" />
|
||||
|
||||
</Target>
|
||||
|
||||
|
||||
|
||||
</Project>
|
@@ -58,5 +58,5 @@ public class TDHistoryValue : STable
|
||||
/// </summary>
|
||||
[Description("变量值")]
|
||||
[SugarColumn(Length = 18, DecimalDigits = 2)]
|
||||
public double Value { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ namespace ThingsGateway.Plugin.TDengineDB;
|
||||
/// <summary>
|
||||
/// SQLDB
|
||||
/// </summary>
|
||||
public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue>
|
||||
public partial class TDengineDB : UpLoadBaseWithCacheT<DeviceData, TDHistoryValue>
|
||||
{
|
||||
protected override bool _device => false;
|
||||
protected override bool _variable => true;
|
||||
@@ -41,7 +41,7 @@ public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue
|
||||
public override VariablePropertyBase VariablePropertys => _variablePropertys;
|
||||
protected override IReadWrite _readWrite => null;
|
||||
|
||||
protected override UploadPropertyWithCache _uploadPropertyWithCache => _driverPropertys;
|
||||
protected override UploadPropertyWithCacheT _uploadPropertyWithCache => _driverPropertys;
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
@@ -59,7 +59,7 @@ public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue
|
||||
{
|
||||
_config = new TypeAdapterConfig();
|
||||
_config.ForType<DeviceVariableRunTime, TDHistoryValue>()
|
||||
.Map(dest => dest.Value, (src) => ValueReturn(src));
|
||||
.Map(dest => dest.Value, src => src.Value == null ? string.Empty : src.Value.ToString() ?? string.Empty);
|
||||
base.Init(client);
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,6 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
|
||||
using ThingsGateway.Foundation.Extension.Generic;
|
||||
using ThingsGateway.Foundation.Extension.String;
|
||||
|
||||
using Yitter.IdGenerator;
|
||||
|
||||
@@ -31,7 +30,7 @@ namespace ThingsGateway.Plugin.TDengineDB;
|
||||
/// <summary>
|
||||
/// MqttClient
|
||||
/// </summary>
|
||||
public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue>
|
||||
public partial class TDengineDB : UpLoadBaseWithCacheT<DeviceData, TDHistoryValue>
|
||||
{
|
||||
private const string devType = "dev";
|
||||
private const string varType = "var";
|
||||
@@ -39,19 +38,6 @@ public partial class TDengineDB : UpLoadBaseWithCache<DeviceData, TDHistoryValue
|
||||
private readonly TDengineDBVariableProperty _variablePropertys = new();
|
||||
|
||||
private volatile bool success = true;
|
||||
private static object ValueReturn(DeviceVariableRunTime src)
|
||||
{
|
||||
var data = src.Value?.ToString()?.ToBool();
|
||||
if (data != null)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return src.Value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void AddCache(List<CacheItem> cacheItems, IEnumerable<TDHistoryValue> dev)
|
||||
{
|
||||
var data = dev.ChunkBetter(_driverPropertys.CacheItemCount);
|
||||
|
@@ -17,7 +17,7 @@ namespace ThingsGateway.Plugin.TDengineDB;
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public class TDengineDBProperty : UploadPropertyWithCache
|
||||
public class TDengineDBProperty : UploadPropertyWithCacheT
|
||||
{
|
||||
|
||||
public DbType DbType { get; set; } = DbType.TDengine;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>4.0.0.0</Version>
|
||||
<Version>4.0.0.3</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TargetFrameworks>net6.0;net8.0;</TargetFrameworks>
|
||||
|
@@ -54,20 +54,6 @@ public class Program
|
||||
builder.Host.UseWindowsService();
|
||||
builder.Host.UseSystemd();
|
||||
|
||||
#if AF2021
|
||||
|
||||
builder.WebHost.UseKestrel(
|
||||
o =>
|
||||
{
|
||||
var config = Furion.App.GetConfig<ThingsGateway.Gateway.LK.MqttConfig>("MqttConfig", true);
|
||||
if (config.Enable)
|
||||
{
|
||||
o.ListenAnyIP(config.Port, a => MQTTnet.AspNetCore.ConnectionBuilderExtensions.UseMqtt(a));
|
||||
o.ListenAnyIP(config.WebSocketPort);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
//Furion便利方法
|
||||
builder.Inject();
|
||||
var app = builder.Build();
|
||||
|
@@ -7,15 +7,6 @@
|
||||
<!--<PlatformTarget>x86</PlatformTarget>-->
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<_WebToolingArtifacts Remove="Properties\PublishProfiles\linux64_net6.pubxml" />
|
||||
<_WebToolingArtifacts Remove="Properties\PublishProfiles\linux64_net7.pubxml" />
|
||||
<_WebToolingArtifacts Remove="Properties\PublishProfiles\win64_net6.pubxml" />
|
||||
<_WebToolingArtifacts Remove="Properties\PublishProfiles\win64_net7.pubxml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="pm2-linux.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
@@ -53,17 +44,5 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--pro内容-->
|
||||
<PropertyGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro - AF2021'">
|
||||
<DefineConstants>AF2021</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition="'$(SolutionName)'=='ThingsGateway - Pro - AF2021'">
|
||||
<ProjectReference Include="..\..\PluginProAF2021\ThingsGateway.Gateway.LK\ThingsGateway.Gateway.LK.csproj" />
|
||||
<PackageReference Include="MQTTnet.AspNetCore" Version="4.3.1.873" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
|
Reference in New Issue
Block a user