添加 脚本调试项目

This commit is contained in:
2248356998 qq.com
2025-09-22 10:36:28 +08:00
parent 58e099cb93
commit 4a7534b210
18 changed files with 691 additions and 604 deletions

View File

@@ -1,11 +1,11 @@
<Project>
<PropertyGroup>
<PluginVersion>10.11.58</PluginVersion>
<ProPluginVersion>10.11.58</ProPluginVersion>
<DefaultVersion>10.11.58</DefaultVersion>
<AuthenticationVersion>10.11.5</AuthenticationVersion>
<SourceGeneratorVersion>10.11.4</SourceGeneratorVersion>
<PluginVersion>10.11.62</PluginVersion>
<ProPluginVersion>10.11.62</ProPluginVersion>
<DefaultVersion>10.11.62</DefaultVersion>
<AuthenticationVersion>10.11.6</AuthenticationVersion>
<SourceGeneratorVersion>10.11.6</SourceGeneratorVersion>
<NET8Version>8.0.20</NET8Version>
<NET9Version>9.0.9</NET9Version>
<SatelliteResourceLanguages>zh-Hans;en-US</SatelliteResourceLanguages>

View File

@@ -20,9 +20,9 @@ namespace BenchmarkConsoleApp
{
internal class Program
{
public static int ClientCount = 30;
public static int TaskNumberOfItems = 30;
public static int NumberOfItems = 30;
public static int ClientCount = 3;
public static int TaskNumberOfItems = 1;
public static int NumberOfItems = 3;
private static async Task Main(string[] args)
{

View File

@@ -13,7 +13,7 @@
<ProjectReference Include="..\..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj">
</ProjectReference>
<ProjectReference Include="..\ThingsGateway.Foundation.Dlt645\ThingsGateway.Foundation.Dlt645.csproj">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</ProjectReference>
</ItemGroup>

View File

@@ -11,7 +11,7 @@
<ProjectReference Include="..\..\Gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj">
</ProjectReference>
<PackageReference Include="Confluent.Kafka" Version="2.11.1" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
</ItemGroup>

View File

@@ -13,7 +13,7 @@
<ProjectReference Include="..\..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj">
</ProjectReference>
<ProjectReference Include="..\ThingsGateway.Foundation.Modbus\ThingsGateway.Foundation.Modbus.csproj">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</ProjectReference>
</ItemGroup>

View File

@@ -27,21 +27,21 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
<PackageReference Include="MQTTnet.AspNetCore" Version="4.3.7.1207" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<PackageReference Include="MQTTnet" Version="4.3.7.1207" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net6.0' ">
<PackageReference Include="MQTTnet.Server" Version="5.0.1.1416" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<PackageReference Include="MQTTnet.AspNetCore" Version="5.0.1.1416" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<PackageReference Include="MQTTnet" Version="5.0.1.1416" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
</ItemGroup>

View File

@@ -24,7 +24,7 @@
<ProjectReference Include="..\..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj">
</ProjectReference>
<ProjectReference Include="..\ThingsGateway.Foundation.OpcDa\ThingsGateway.Foundation.OpcDa.csproj">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</ProjectReference>
</ItemGroup>

View File

@@ -26,31 +26,31 @@
<ProjectReference Include="..\ThingsGateway.Foundation.OpcUa\ThingsGateway.Foundation.OpcUa.csproj" />
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Server" Version="1.5.376.244" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client.ComplexTypes" Version="1.5.376.244" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.5.376.244" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Core" Version="1.5.376.244" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Configuration" Version="1.5.376.244" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Security.Certificates" Version="1.5.376.244" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
<!--<PackageReference Include="System.Formats.Asn1" Version="8.0.2" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>-->
</ItemGroup>

View File

@@ -15,7 +15,7 @@
<ItemGroup>
<PackageReference Include="RabbitMQ.Client" Version="7.1.2" GeneratePathProperty="true">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</PackageReference>
</ItemGroup>

View File

@@ -13,7 +13,7 @@
<ProjectReference Include="..\..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj">
</ProjectReference>
<ProjectReference Include="..\ThingsGateway.Foundation.SiemensS7\ThingsGateway.Foundation.SiemensS7.csproj">
<PrivateAssets>contentFiles;compile;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
<PrivateAssets>contentFiles;build;buildMultitargeting;buildTransitive;analyzers;</PrivateAssets>
</ProjectReference>
</ItemGroup>

View File

@@ -0,0 +1,52 @@
//------------------------------------------------------------------------------
//此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
// ------------------------------------------------------------------------------
using MQTTnet;
using Newtonsoft.Json.Linq;
using System.Text;
using ThingsGateway.Foundation;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.Plugin.Mqtt;
using TouchSocket.Core;
public class TestClientRpc : DynamicMqttClientRpcBase
{
public override async Task RPCInvokeAsync(ILog logMessage, MqttApplicationMessageReceivedEventArgs args, MqttClientProperty driverPropertys, IMqttClient mqttClient, Func<string, Dictionary<string, Dictionary<string, JToken>>, ValueTask<Dictionary<string, Dictionary<string, IOperResult>>>> getRpcResult, Func<CancellationToken, ValueTask<OperResult>> tryMqttClientAsync, CancellationToken cancellationToken)
{
if (driverPropertys.RpcWriteTopic.IsNullOrWhiteSpace()) return;
var t = string.Format(null, "{0}/+", driverPropertys.RpcWriteTopic);
if (MqttTopicFilterComparer.Compare(args.ApplicationMessage.Topic, t) != MqttTopicFilterCompareResult.IsMatch)
return;
var rpcDatas = Encoding.UTF8.GetString(args.ApplicationMessage.Payload).FromJsonNetString<Dictionary<string, Dictionary<string, JToken>>>();
if (rpcDatas == null)
return;
var mqttRpcResult = await getRpcResult(args.ClientId, rpcDatas).ConfigureAwait(false);
try
{
var isConnect = await tryMqttClientAsync(CancellationToken.None).ConfigureAwait(false);
if (isConnect.IsSuccess)
{
var variableMessage = new MqttApplicationMessageBuilder()
.WithTopic($"{args.ApplicationMessage.Topic}/Response")
.WithPayload(mqttRpcResult.ToSystemTextJsonString(driverPropertys.JsonFormattingIndented)).Build();
await mqttClient.PublishAsync(variableMessage, cancellationToken).ConfigureAwait(false);
}
}
catch
{
}
}
}

View File

@@ -1,263 +1,263 @@

//using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;
//using ThingsGateway.Foundation;
//using ThingsGateway.Gateway.Application;
//namespace ThingsGateway.Server;
using ThingsGateway.Foundation;
using ThingsGateway.Gateway.Application;
namespace ThingsGateway.Server;
///// <summary>
///// 插件类,默认实现了<see cref="IDevice"/>接口,继承<see cref="CollectFoundationBase"/> 实现采集插件
///// </summary>
//public class TestCollectPlugin : CollectFoundationBase
//{
// /// <summary>
// /// 调试UI Type如果不存在无需重写
// /// </summary>
// public override Type DriverDebugUIType => base.DriverDebugUIType;
// /// <summary>
// /// 插件属性UI Type继承<see cref="IPropertyUIBase"/>如果不存在无需重写
// /// </summary>
// public override Type DriverPropertyUIType => base.DriverPropertyUIType;
// /// <summary>
// /// 插件UI Type继承<see cref="IDriverUIBase"/>如果不存在无需重写
// /// </summary>
// public override Type DriverUIType => base.DriverUIType;
// /// <summary>
// /// 插件变量寄存器UI Type继承<see cref="IAddressUIBase"/>如果不存在无需重写
// /// </summary>
// public override Type DriverVariableAddressUIType => base.DriverVariableAddressUIType;
/// <summary>
/// 插件类,默认实现了<see cref="IDevice"/>接口,继承<see cref="CollectFoundationBase"/> 实现采集插件
/// </summary>
public class TestCollectPlugin : CollectFoundationBase
{
/// <summary>
/// 调试UI Type如果不存在无需重写
/// </summary>
public override Type DriverDebugUIType => base.DriverDebugUIType;
/// <summary>
/// 插件属性UI Type继承<see cref="IPropertyUIBase"/>如果不存在无需重写
/// </summary>
public override Type DriverPropertyUIType => base.DriverPropertyUIType;
/// <summary>
/// 插件UI Type继承<see cref="IDriverUIBase"/>如果不存在无需重写
/// </summary>
public override Type DriverUIType => base.DriverUIType;
/// <summary>
/// 插件变量寄存器UI Type继承<see cref="IAddressUIBase"/>如果不存在无需重写
/// </summary>
public override Type DriverVariableAddressUIType => base.DriverVariableAddressUIType;
// /// <summary>
// /// 插件配置项,继承<see cref="CollectPropertyBase"/> 返回类实例
// /// </summary>
// public override CollectPropertyBase CollectProperties => _property;
// private TestCollectProperty? _property = new();
/// <summary>
/// 插件配置项,继承<see cref="CollectPropertyBase"/> 返回类实例
/// </summary>
public override CollectPropertyBase CollectProperties => _property;
private TestCollectProperty? _property = new();
// /// <summary>
// /// 在插件初始化时调用只会执行一次参数为插件默认的链路通道类如未实现可忽略l
// /// </summary>
// protected override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
// {
// //做一些初始化操作
/// <summary>
/// 在插件初始化时调用只会执行一次参数为插件默认的链路通道类如未实现可忽略l
/// </summary>
protected override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
{
//做一些初始化操作
// return Task.CompletedTask;
// }
return Task.CompletedTask;
}
// /// <summary>
// /// 变量打包操作会在默认的AfterVariablesChangedAsync方法里执行参数为设备变量列表返回源读取变量列表
// /// </summary>
// protected override Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables)
// {
// //实现将设备变量打包成源读取变量
// //比如如果需要实现MC中的字多读功能需将多个变量地址打包成一个源读取地址和读取长度根据一系列规则添加解析标识然后在返回的整个字节数组中解析出原来的变量地址代表的数据字节
/// <summary>
/// 变量打包操作会在默认的AfterVariablesChangedAsync方法里执行参数为设备变量列表返回源读取变量列表
/// </summary>
protected override Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables)
{
//实现将设备变量打包成源读取变量
//比如如果需要实现MC中的字多读功能需将多个变量地址打包成一个源读取地址和读取长度根据一系列规则添加解析标识然后在返回的整个字节数组中解析出原来的变量地址代表的数据字节
// //一般可操作 VariableRuntime 类中的 index, thingsgatewaybitconvter 等属性
// //一般可操作 VariableSourceRead 类中的 address, length 等属性
//一般可操作 VariableRuntime 类中的 index, thingsgatewaybitconvter 等属性
//一般可操作 VariableSourceRead 类中的 address, length 等属性
// return Task.FromResult(new List<VariableSourceRead>());
// }
return Task.FromResult(new List<VariableSourceRead>());
}
// /// <summary>
// /// 实现<see cref="IDevice"/>
// /// </summary>
// public override IDevice? FoundationDevice => base.FoundationDevice;
/// <summary>
/// 实现<see cref="IDevice"/>
/// </summary>
public override IDevice? FoundationDevice => base.FoundationDevice;
// /// <summary>
// /// 特殊方法,添加<see cref="DynamicMethodAttribute"/> 特性 返回IOperResult
// /// 支持<see cref="CancellationToken"/> 参数,需放到最后
// /// 默认解析方式为英文分号
// /// 比如rpc参数为 test1;test2解析query1="test1",query2="test2"
// /// 也可以在变量地址中填入test1rpc参数传入test2解析query1="test1",query2="test2"
// /// </summary>
// [DynamicMethod("测试特殊方法")]
// public IOperResult<string> TestMethod(string query1, string query2, CancellationToken cancellationToken)
// {
// return new OperResult<string>() { Content = "测试特殊方法" };
// }
//}
/// <summary>
/// 特殊方法,添加<see cref="DynamicMethodAttribute"/> 特性 返回IOperResult
/// 支持<see cref="CancellationToken"/> 参数,需放到最后
/// 默认解析方式为英文分号
/// 比如rpc参数为 test1;test2解析query1="test1",query2="test2"
/// 也可以在变量地址中填入test1rpc参数传入test2解析query1="test1",query2="test2"
/// </summary>
[DynamicMethod("测试特殊方法")]
public IOperResult<string> TestMethod(string query1, string query2, CancellationToken cancellationToken)
{
return new OperResult<string>() { Content = "测试特殊方法" };
}
}
///// <summary>
///// 插件类配置
///// </summary>
//public class TestCollectProperty : CollectFoundationPackPropertyBase
//{
// /// <summary>
// /// 添加<see cref="DynamicPropertyAttribute"/> 特性如需多语言配置可添加json资源参考其他插件
// /// </summary>
// [DynamicProperty(Description = null, Remark = null)]
// public string TestString { get; set; }
/// <summary>
/// 插件类配置
/// </summary>
public class TestCollectProperty : CollectFoundationPackPropertyBase
{
/// <summary>
/// 添加<see cref="DynamicPropertyAttribute"/> 特性如需多语言配置可添加json资源参考其他插件
/// </summary>
[DynamicProperty(Description = null, Remark = null)]
public string TestString { get; set; }
//}
}
///// <summary>
///// 插件类,完全自定义
///// </summary>
//public class TestCollectPlugin1 : CollectBase
//{
// /// <summary>
// /// 调试UI Type如果不存在无需重写
// /// </summary>
// public override Type DriverDebugUIType => base.DriverDebugUIType;
// /// <summary>
// /// 插件属性UI Type继承<see cref="IPropertyUIBase"/>如果不存在无需重写
// /// </summary>
// public override Type DriverPropertyUIType => base.DriverPropertyUIType;
// /// <summary>
// /// 插件UI Type继承<see cref="IDriverUIBase"/>如果不存在无需重写
// /// </summary>
// public override Type DriverUIType => base.DriverUIType;
// /// <summary>
// /// 插件变量寄存器UI Type继承<see cref="IAddressUIBase"/>如果不存在无需重写
// /// </summary>
// public override Type DriverVariableAddressUIType => base.DriverVariableAddressUIType;
/// <summary>
/// 插件类,完全自定义
/// </summary>
public class TestCollectPlugin1 : CollectBase
{
/// <summary>
/// 调试UI Type如果不存在无需重写
/// </summary>
public override Type DriverDebugUIType => base.DriverDebugUIType;
/// <summary>
/// 插件属性UI Type继承<see cref="IPropertyUIBase"/>如果不存在无需重写
/// </summary>
public override Type DriverPropertyUIType => base.DriverPropertyUIType;
/// <summary>
/// 插件UI Type继承<see cref="IDriverUIBase"/>如果不存在无需重写
/// </summary>
public override Type DriverUIType => base.DriverUIType;
/// <summary>
/// 插件变量寄存器UI Type继承<see cref="IAddressUIBase"/>如果不存在无需重写
/// </summary>
public override Type DriverVariableAddressUIType => base.DriverVariableAddressUIType;
// /// <summary>
// /// 插件配置项,继承<see cref="CollectPropertyBase"/> 返回类实例
// /// </summary>
// public override CollectPropertyBase CollectProperties => _property;
// private TestCollectProperty1? _property = new();
/// <summary>
/// 插件配置项,继承<see cref="CollectPropertyBase"/> 返回类实例
/// </summary>
public override CollectPropertyBase CollectProperties => _property;
private TestCollectProperty1? _property = new();
// /// <summary>
// /// 在插件初始化时调用只会执行一次参数为插件默认的链路通道类如未实现可忽略l
// /// </summary>
// protected override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
// {
// //做一些初始化操作
/// <summary>
/// 在插件初始化时调用只会执行一次参数为插件默认的链路通道类如未实现可忽略l
/// </summary>
protected override Task InitChannelAsync(IChannel? channel, CancellationToken cancellationToken)
{
//做一些初始化操作
// return Task.CompletedTask;
// }
return Task.CompletedTask;
}
// /// <summary>
// /// 变量打包操作会在默认的AfterVariablesChangedAsync方法里执行参数为设备变量列表返回源读取变量列表
// /// </summary>
// protected override Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables)
// {
// //实现将设备变量打包成源读取变量
// //比如如果需要实现MC中的字多读功能需将多个变量地址打包成一个源读取地址和读取长度根据一系列规则添加解析标识然后在返回的整个字节数组中解析出原来的变量地址代表的数据字节
/// <summary>
/// 变量打包操作会在默认的AfterVariablesChangedAsync方法里执行参数为设备变量列表返回源读取变量列表
/// </summary>
protected override Task<List<VariableSourceRead>> ProtectedLoadSourceReadAsync(List<VariableRuntime> deviceVariables)
{
//实现将设备变量打包成源读取变量
//比如如果需要实现MC中的字多读功能需将多个变量地址打包成一个源读取地址和读取长度根据一系列规则添加解析标识然后在返回的整个字节数组中解析出原来的变量地址代表的数据字节
// //一般可操作 VariableRuntime 类中的 index, thingsgatewaybitconvter 等属性
// //一般可操作 VariableSourceRead 类中的 address, length 等属性
//一般可操作 VariableRuntime 类中的 index, thingsgatewaybitconvter 等属性
//一般可操作 VariableSourceRead 类中的 address, length 等属性
// return Task.FromResult(new List<VariableSourceRead>());
// }
return Task.FromResult(new List<VariableSourceRead>());
}
// /// <summary>
// /// 如果不实现ReadSourceAsync方法可以返回flase
// /// </summary>
// protected override bool VariableSourceReadsEnable => base.VariableSourceReadsEnable;
/// <summary>
/// 如果不实现ReadSourceAsync方法可以返回flase
/// </summary>
protected override bool VariableSourceReadsEnable => base.VariableSourceReadsEnable;
// /// <summary>
// /// 获取任务列表,默认会实现 TestOnline任务SetDeviceStatus任务以及 VariableSourceRead等任务VariableSourceRead任务启用条件为<see cref="VariableSourceReadsEnable"/> 为true。任务即是timer实现可通过<see cref="ScheduledTaskHelper.GetTask(string, Func{object?, CancellationToken, Task}, object?, TouchSocket.Core.ILog, CancellationToken)"/> 方法实现定时任务
// /// </summary>
// /// <param name="cancellationToken"></param>
// /// <returns></returns>
// protected override List<IScheduledTask> ProtectedGetTasks(CancellationToken cancellationToken)
// {
// return base.ProtectedGetTasks(cancellationToken);
// }
/// <summary>
/// 获取任务列表,默认会实现 TestOnline任务SetDeviceStatus任务以及 VariableSourceRead等任务VariableSourceRead任务启用条件为<see cref="VariableSourceReadsEnable"/> 为true。任务即是timer实现可通过<see cref="ScheduledTaskHelper.GetTask(string, Func{object?, CancellationToken, Task}, object?, TouchSocket.Core.ILog, CancellationToken)"/> 方法实现定时任务
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected override List<IScheduledTask> ProtectedGetTasks(CancellationToken cancellationToken)
{
return base.ProtectedGetTasks(cancellationToken);
}
// /// <summary>
// /// 实现离线重连任务
// /// </summary>
// /// <param name="state"></param>
// /// <param name="cancellationToken"></param>
// /// <returns></returns>
// protected override Task TestOnline(object? state, CancellationToken cancellationToken)
// {
// return base.TestOnline(state, cancellationToken);
// }
/// <summary>
/// 实现离线重连任务
/// </summary>
/// <param name="state"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected override Task TestOnline(object? state, CancellationToken cancellationToken)
{
return base.TestOnline(state, cancellationToken);
}
// /// <summary>
// /// 返回是否成功连接设备
// /// </summary>
// /// <returns></returns>
// public override bool IsConnected()
// {
// return true;
// }
/// <summary>
/// 返回是否成功连接设备
/// </summary>
/// <returns></returns>
public override bool IsConnected()
{
return true;
}
// /// <summary>
// /// 在变量发生组态变化后执行,默认会执行<see cref="ProtectedLoadSourceReadAsync"/> 方法重新获取源读取变量列表并且重新启动VariableSourceRead等任务
// /// </summary>
// /// <param name="cancellationToken"></param>
// /// <returns></returns>
// public override Task AfterVariablesChangedAsync(CancellationToken cancellationToken)
// {
// return base.AfterVariablesChangedAsync(cancellationToken);
// }
/// <summary>
/// 在变量发生组态变化后执行,默认会执行<see cref="ProtectedLoadSourceReadAsync"/> 方法重新获取源读取变量列表并且重新启动VariableSourceRead等任务
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override Task AfterVariablesChangedAsync(CancellationToken cancellationToken)
{
return base.AfterVariablesChangedAsync(cancellationToken);
}
// /// <summary>
// /// 变量寄存器的字符串描述
// /// </summary>
// /// <returns></returns>
// public override string GetAddressDescription()
// {
// return base.GetAddressDescription();
// }
/// <summary>
/// 变量寄存器的字符串描述
/// </summary>
/// <returns></returns>
public override string GetAddressDescription()
{
return base.GetAddressDescription();
}
// /// <summary>
// /// 设备暂停时执行,默认会暂停所有任务
// /// </summary>
// /// <param name="pause"></param>
// public override void PauseThread(bool pause)
// {
// base.PauseThread(pause);
// }
/// <summary>
/// 设备暂停时执行,默认会暂停所有任务
/// </summary>
/// <param name="pause"></param>
public override void PauseThread(bool pause)
{
base.PauseThread(pause);
}
// /// <summary>
// /// 开始前执行
// /// </summary>
// protected override Task ProtectedStartAsync(CancellationToken cancellationToken)
// {
// //一般实现PLC长连接
// return base.ProtectedStartAsync(cancellationToken);
// }
/// <summary>
/// 开始前执行
/// </summary>
protected override Task ProtectedStartAsync(CancellationToken cancellationToken)
{
//一般实现PLC长连接
return base.ProtectedStartAsync(cancellationToken);
}
// /// <summary>
// /// 写入变量,实现设备写入操作,注意执行写锁, using var writeLock =await ReadWriteLock.WriterLockAsync(cancellationToken).ConfigureAwait(false);
// /// </summary>
// protected override ValueTask<Dictionary<string, OperResult>> WriteValuesAsync(Dictionary<VariableRuntime, JToken> writeInfoLists, CancellationToken cancellationToken)
// {
// return base.WriteValuesAsync(writeInfoLists, cancellationToken);
// }
/// <summary>
/// 写入变量,实现设备写入操作,注意执行写锁, using var writeLock =await ReadWriteLock.WriterLockAsync(cancellationToken).ConfigureAwait(false);
/// </summary>
protected override ValueTask<Dictionary<string, OperResult>> WriteValuesAsync(Dictionary<VariableRuntime, JToken> writeInfoLists, CancellationToken cancellationToken)
{
return base.WriteValuesAsync(writeInfoLists, cancellationToken);
}
// /// <summary>
// /// 读取源变量,在<see cref="VariableSourceReadsEnable"/> 为true时添加源读取任务任务启动时会执行
// /// 一般需要更新设备变量值,调用<see cref="VariableRuntime.SetValue(object?, DateTime, bool)"/>
// /// </summary>
// protected override ValueTask<OperResult<ReadOnlyMemory<byte>>> ReadSourceAsync(VariableSourceRead variableSourceRead, CancellationToken cancellationToken)
// {
// return base.ReadSourceAsync(variableSourceRead, cancellationToken);
// }
/// <summary>
/// 读取源变量,在<see cref="VariableSourceReadsEnable"/> 为true时添加源读取任务任务启动时会执行
/// 一般需要更新设备变量值,调用<see cref="VariableRuntime.SetValue(object?, DateTime, bool)"/>
/// </summary>
protected override ValueTask<OperResult<ReadOnlyMemory<byte>>> ReadSourceAsync(VariableSourceRead variableSourceRead, CancellationToken cancellationToken)
{
return base.ReadSourceAsync(variableSourceRead, cancellationToken);
}
// protected override Task DisposeAsync(bool disposing)
// {
// return base.DisposeAsync(disposing);
// }
protected override Task DisposeAsync(bool disposing)
{
return base.DisposeAsync(disposing);
}
// /// <summary>
// /// 特殊方法,添加<see cref="DynamicMethodAttribute"/> 特性 返回IOperResult
// /// 支持<see cref="CancellationToken"/> 参数,需放到最后
// /// 默认解析方式为英文分号
// /// 比如rpc参数为 test1;test2解析query1="test1",query2="test2"
// /// 也可以在变量地址中填入test1rpc参数传入test2解析query1="test1",query2="test2"
// /// </summary>
// [DynamicMethod("测试特殊方法")]
// public IOperResult<string> TestMethod(string query1, string query2, CancellationToken cancellationToken)
// {
// return new OperResult<string>() { Content = "测试特殊方法" };
// }
//}
/// <summary>
/// 特殊方法,添加<see cref="DynamicMethodAttribute"/> 特性 返回IOperResult
/// 支持<see cref="CancellationToken"/> 参数,需放到最后
/// 默认解析方式为英文分号
/// 比如rpc参数为 test1;test2解析query1="test1",query2="test2"
/// 也可以在变量地址中填入test1rpc参数传入test2解析query1="test1",query2="test2"
/// </summary>
[DynamicMethod("测试特殊方法")]
public IOperResult<string> TestMethod(string query1, string query2, CancellationToken cancellationToken)
{
return new OperResult<string>() { Content = "测试特殊方法" };
}
}
///// <summary>
///// 插件类配置
///// </summary>
//public class TestCollectProperty1 : CollectPropertyBase
//{
// /// <summary>
// /// 添加<see cref="DynamicPropertyAttribute"/> 特性如需多语言配置可添加json资源参考其他插件
// /// </summary>
// [DynamicProperty(Description = null, Remark = null)]
// public string TestString { get; set; }
/// <summary>
/// 插件类配置
/// </summary>
public class TestCollectProperty1 : CollectPropertyBase
{
/// <summary>
/// 添加<see cref="DynamicPropertyAttribute"/> 特性如需多语言配置可添加json资源参考其他插件
/// </summary>
[DynamicProperty(Description = null, Remark = null)]
public string TestString { get; set; }
//}
}

View File

@@ -1,56 +1,56 @@
//////------------------------------------------------------------------------------
//////此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
////// 此代码版权除特别声明外的代码归作者本人Diego所有
////// 源代码使用协议遵循本仓库的开源协议及附加协议
////// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
////// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
////// 使用文档https://thingsgateway.cn/
////// QQ群605534569
////// ------------------------------------------------------------------------------
////------------------------------------------------------------------------------
////此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
//// 此代码版权除特别声明外的代码归作者本人Diego所有
//// 源代码使用协议遵循本仓库的开源协议及附加协议
//// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
//// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
//// 使用文档https://thingsgateway.cn/
//// QQ群605534569
//// ------------------------------------------------------------------------------
//using System.Dynamic;
using System.Dynamic;
//using ThingsGateway.Foundation;
//using ThingsGateway.Gateway.Application;
//public class TestDynamicModel : IDynamicModel
//{
// public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
// {
// if (datas == null) return null;
// List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
// //按设备名称分组
// var groups = datas.Where(a => !string.IsNullOrEmpty(((AlarmVariable)a).DeviceName)).GroupBy(a => ((AlarmVariable)a).DeviceName, a => ((AlarmVariable)a));
// foreach (var group in groups)
// {
// //按采集时间分组
// var data = group.GroupBy(a => a.AlarmTime.DateTimeToUnixTimestamp());
// var deviceObj = new ExpandoObject();
// List<ExpandoObject> expandos = new List<ExpandoObject>();
// foreach (var item in data)
// {
// var expando = new ExpandoObject();
// expando.TryAdd("ts", item.Key);
// var variableObj = new ExpandoObject();
// foreach (var tag in item)
// {
// var alarmObj = new ExpandoObject();
// alarmObj.TryAdd(nameof(tag.AlarmCode), tag.AlarmCode);
// alarmObj.TryAdd(nameof(tag.AlarmText), tag.AlarmText);
// alarmObj.TryAdd(nameof(tag.AlarmType), tag.AlarmType);
// alarmObj.TryAdd(nameof(tag.AlarmLimit), tag.AlarmLimit);
// alarmObj.TryAdd(nameof(tag.EventTime), tag.EventTime);
// alarmObj.TryAdd(nameof(tag.EventType), tag.EventType);
using ThingsGateway.Foundation;
using ThingsGateway.Gateway.Application;
public class TestDynamicModel : IDynamicModel
{
public IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
if (datas == null) return null;
List<ExpandoObject> deviceObjs = new List<ExpandoObject>();
//按设备名称分组
var groups = datas.Where(a => !string.IsNullOrEmpty(((AlarmVariable)a).DeviceName)).GroupBy(a => ((AlarmVariable)a).DeviceName, a => ((AlarmVariable)a));
foreach (var group in groups)
{
//按采集时间分组
var data = group.GroupBy(a => a.AlarmTime.DateTimeToUnixTimestamp());
var deviceObj = new ExpandoObject();
List<ExpandoObject> expandos = new List<ExpandoObject>();
foreach (var item in data)
{
var expando = new ExpandoObject();
expando.TryAdd("ts", item.Key);
var variableObj = new ExpandoObject();
foreach (var tag in item)
{
var alarmObj = new ExpandoObject();
alarmObj.TryAdd(nameof(tag.AlarmCode), tag.AlarmCode);
alarmObj.TryAdd(nameof(tag.AlarmText), tag.AlarmText);
alarmObj.TryAdd(nameof(tag.AlarmType), tag.AlarmType);
alarmObj.TryAdd(nameof(tag.AlarmLimit), tag.AlarmLimit);
alarmObj.TryAdd(nameof(tag.EventTime), tag.EventTime);
alarmObj.TryAdd(nameof(tag.EventType), tag.EventType);
// variableObj.TryAdd(tag.Name, alarmObj);
// }
// expando.TryAdd("alarms", variableObj);
variableObj.TryAdd(tag.Name, alarmObj);
}
expando.TryAdd("alarms", variableObj);
// expandos.Add(expando);
// }
// deviceObj.TryAdd(group.Key, expandos);
// deviceObjs.Add(deviceObj);
// }
expandos.Add(expando);
}
deviceObj.TryAdd(group.Key, expandos);
deviceObjs.Add(deviceObj);
}
// return deviceObjs;
// }
//}
return deviceObjs;
}
}

View File

@@ -1,46 +1,46 @@

//using System.Text;
using System.Text;
//using ThingsGateway.Gateway.Application;
using ThingsGateway.Gateway.Application;
//public class TestExexcuteExpressions : IExexcuteExpressions
//{
public class TestExexcuteExpressions : IExexcuteExpressions
{
// public TouchSocket.Core.ILog Logger { get; set; }
public TouchSocket.Core.ILog Logger { get; set; }
// public async System.Threading.Tasks.Task<NodeOutput> ExecuteAsync(NodeInput input, System.Threading.CancellationToken cancellationToken)
// {
// //想上传mqtt可以自己写mqtt上传代码或者通过mqtt插件的公开方法上传
public async System.Threading.Tasks.Task<NodeOutput> ExecuteAsync(NodeInput input, System.Threading.CancellationToken cancellationToken)
{
//想上传mqtt可以自己写mqtt上传代码或者通过mqtt插件的公开方法上传
// //直接获取mqttclient插件类型的第一个设备
// var mqttClient = GlobalData.ReadOnlyChannels.FirstOrDefault(a => a.Value.PluginName == "ThingsGateway.Plugin.Mqtt.MqttClient").Value?.ReadDeviceRuntimes?.FirstOrDefault().Value?.Driver as ThingsGateway.Plugin.Mqtt.MqttClient;
// if (mqttClient == null)
// throw new("mqttClient NOT FOUND");
//直接获取mqttclient插件类型的第一个设备
//var mqttClient = GlobalData.ReadOnlyChannels.FirstOrDefault(a => a.Value.PluginName == "ThingsGateway.Plugin.Mqtt.MqttClient").Value?.ReadDeviceRuntimes?.FirstOrDefault().Value?.Driver as ThingsGateway.Plugin.Mqtt.MqttClient;
//if (mqttClient == null)
// throw new("mqttClient NOT FOUND");
// TopicArray topicArray = new()
// {
// Topic = "test",
// Payload = Encoding.UTF8.GetBytes("test")
// };
// var result = await mqttClient.MqttUpAsync(topicArray, default).ConfigureAwait(false);// 主题 和 负载
// if (!result.IsSuccess)
// throw new(result.ErrorMessage);
// return new NodeOutput() { Value = result };
//TopicArray topicArray = new()
//{
// Topic = "test",
// Payload = Encoding.UTF8.GetBytes("test")
//};
//var result = await mqttClient.MqttUpAsync(topicArray, default).ConfigureAwait(false);// 主题 和 负载
//if (!result.IsSuccess)
// throw new(result.ErrorMessage);
//return new NodeOutput() { Value = result };
// //通过设备名称找出mqttClient插件
// //var mqttClient = GlobalData.ReadOnlyDevices.FirstOrDefault(a => a.Value.Name == "mqttDevice1").Value?.Driver as ThingsGateway.Plugin.Mqtt.MqttClient;
//通过设备名称找出mqttClient插件
var mqttClient = GlobalData.ReadOnlyDevices.FirstOrDefault(a => a.Value.Name == "mqttDevice1").Value?.Driver as ThingsGateway.Plugin.Mqtt.MqttClient;
// //if (mqttClient == null)
// // throw new("mqttClient NOT FOUND");
if (mqttClient == null)
throw new("mqttClient NOT FOUND");
// //TopicArray topicArray = new()
// //{
// // Topic = "test",
// // Payload = Encoding.UTF8.GetBytes("test")
// //};
// //var result = await mqttClient.MqttUpAsync(topicArray, default).ConfigureAwait(false);// 主题 和 负载
// //if (!result.IsSuccess)
// // throw new(result.ErrorMessage);
// //return new NodeOutput() { Value = result };
// }
//}
TopicArray topicArray = new()
{
Topic = "test",
Payload = Encoding.UTF8.GetBytes("test")
};
var result = await mqttClient.MqttUpAsync(topicArray, default).ConfigureAwait(false);// 主题 和 负载
if (!result.IsSuccess)
throw new(result.ErrorMessage);
return new NodeOutput() { Value = result };
}
}

View File

@@ -1,223 +1,235 @@
//////------------------------------------------------------------------------------
//////此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
////// 此代码版权除特别声明外的代码归作者本人Diego所有
////// 源代码使用协议遵循本仓库的开源协议及附加协议
////// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
////// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
////// 使用文档https://thingsgateway.cn/
////// QQ群605534569
////// ------------------------------------------------------------------------------
using System.Collections.Concurrent;
//using ThingsGateway.Foundation;
//using ThingsGateway.Gateway.Application;
//using ThingsGateway.NewLife.Extension;
//public class TestKafkaDynamicModel : DynamicModelBase
//{
// private Dictionary<string, VariableRuntime> variableRuntimes = new();
using ThingsGateway.Foundation;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Extension;
public class TestKafkaDynamicModel1 : DynamicModelBase
{
private Dictionary<string, VariableRuntime> variableRuntimes = new();
// private long id = 0;
private long id = 0;
// public TestKafkaDynamicModel()
// {
// var name = "kafka1";
// if (GlobalData.ReadOnlyDevices.TryGetValue(name, out var kafka1))
// {
// id = kafka1.Id;
public TestKafkaDynamicModel1()
{
var name = "测试MqttServer";
if (GlobalData.ReadOnlyDevices.TryGetValue(name, out var kafka1))
{
id = kafka1.Id;
// foreach (var item in kafka1.Driver?.IdVariableRuntimes)
// {
// //变量备注1作为Key(AE报警SourceId)
// var data1 = item.Value.GetPropertyValue(id, nameof(BusinessVariableProperty.Data1));
// if (!data1.IsNullOrEmpty())
// {
// variableRuntimes.Add(data1, item.Value);
// }
// }
foreach (var item in kafka1.Driver?.IdVariableRuntimes)
{
//变量备注1作为Key(AE报警SourceId)
var data1 = item.Value.GetPropertyValue(id, nameof(BusinessVariableProperty.Data1));
if (!data1.IsNullOrEmpty())
{
variableRuntimes.Add(data1, item.Value);
}
}
// }
// else
// {
// throw new Exception($"找不到设备 {name}");
// }
}
else
{
throw new Exception($"找不到设备 {name}");
}
// }
// public override IEnumerable<dynamic> GetList(IEnumerable<object> datas)
// {
// if (datas == null) return null;
// var pluginEventDatas = datas.Cast<PluginEventData>();
// var opcDatas = pluginEventDatas.Select(
// a =>
// {
// if (a.ObjectValue == null)
// {
// a.ObjectValue = a.Value.ToObject(Type.GetType(a.ValueType));
// }
// return a.ObjectValue is ThingsGateway.Plugin.OpcAe.OpcAeEventData opcData ? opcData : null;
// }
// ).Where(a => a != null).ToList();
}
// List<KafkaAlarmEntity> alarmEntities = new List<KafkaAlarmEntity>();
// if (opcDatas.Count == 0)
// {
// Logger?.LogInformation("没有OPCAE数据");
// return alarmEntities;
// }
private ConcurrentDictionary<Tuple<string, string, int>, DateTime> EventKeyTimes = new();
public override IEnumerable<dynamic> GetList(IEnumerable<object> datas)
{
if (datas == null) return null;
var pluginEventDatas = datas.Cast<PluginEventData>();
var opcDatas = pluginEventDatas.Select(
a =>
{
if (a.ObjectValue == null)
{
a.ObjectValue = a.Value.ToObject(Type.GetType(a.ValueType));
}
return a.ObjectValue is ThingsGateway.Plugin.OpcAe.OpcAeEventData opcData ? opcData : null;
}
).Where(a => a != null).ToList();
List<KafkaAlarmEntity> alarmEntities = new List<KafkaAlarmEntity>();
if (opcDatas.Count == 0)
{
Logger?.LogInformation("没有OPCAE数据");
return alarmEntities;
}
// foreach (var opcAeEventData in opcDatas)
// {
// //一般只需要条件报警
// //if (opcAeEventData.EventType != Opc.Ae.EventType.Condition)
// // continue;
// //重连时触发的事件,可以跳过不处理
// //if(opcAeEventData.Refresh)
// // continue;
// var sourceName = opcAeEventData.SourceID;
// if (variableRuntimes.TryGetValue(sourceName, out var variableRuntime))
// {
// var ack = opcAeEventData.EventType != Opc.Ae.EventType.Condition ? false : ((Opc.Ae.ConditionState)opcAeEventData.NewState).HasFlag(Opc.Ae.ConditionState.Acknowledged);
foreach (var opcAeEventData in opcDatas)
{
//一般只需要条件报警
//if (opcAeEventData.EventType != Opc.Ae.EventType.Condition)
// continue;
//重连时触发的事件,可以跳过不处理
//if(opcAeEventData.Refresh)
// continue;
var sourceName = opcAeEventData.SourceID;
if (variableRuntimes.TryGetValue(sourceName, out var variableRuntime))
{
var ack = opcAeEventData.EventType != Opc.Ae.EventType.Condition ? false : ((Opc.Ae.ConditionState)opcAeEventData.NewState).HasFlag(Opc.Ae.ConditionState.Acknowledged);
// bool isRecover = opcAeEventData.EventType != Opc.Ae.EventType.Condition ? false : !((Opc.Ae.ConditionState)opcAeEventData.NewState).HasFlag(Opc.Ae.ConditionState.Active);
bool isRecover = opcAeEventData.EventType != Opc.Ae.EventType.Condition ? false : !((Opc.Ae.ConditionState)opcAeEventData.NewState).HasFlag(Opc.Ae.ConditionState.Active);
if (opcAeEventData.EventType != Opc.Ae.EventType.Condition)
{
bool alarm = (opcAeEventData.Message).Contains("raised");
if (alarm)
{
opcAeEventData.AlarmTime = opcAeEventData.Time;
EventKeyTimes.AddOrUpdate(Tuple.Create(opcAeEventData.SourceID, opcAeEventData.ConditionName, opcAeEventData.Cookie), opcAeEventData.Time, (k, v) => opcAeEventData.Time);
}
else
{
if (EventKeyTimes.TryGetValue(Tuple.Create(opcAeEventData.SourceID, opcAeEventData.ConditionName, opcAeEventData.Cookie), out var time))
opcAeEventData.AlarmTime = time;
else
opcAeEventData.AlarmTime = opcAeEventData.Time;
}
isRecover = !alarm;
}
// //构建告警实体
// KafkaAlarmEntity alarmEntity = new KafkaAlarmEntity
// {
// AlarmCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data2)), //唯一编码
// ResourceCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data3)), //资源编码
// ResourceName = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data4)), //资源名称
// MetricCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data5)), //指标编码
// MetricName = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data6)), //指标名称
// Content = $"{variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data4))}{opcAeEventData.Message}", //告警内容,设备名称+告警内容包含阈值信息可能opcae里没有带阈值信息那么就需要录入固定值可选Data10
// AlarmType = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data7)), // opcAeEventData.Severity 告警类型,子系统产生告警的类型,可能需要固定备注值
//构建告警实体
KafkaAlarmEntity alarmEntity = new KafkaAlarmEntity
{
alarmCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data2)), //唯一编码
resourceCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data3)), //资源编码
resourceName = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data4)), //资源名称
metricCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data5)), //指标编码
metricName = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data6)), //指标名称
content = $"{variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data4))}{variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data6))}{opcAeEventData.Message}", //告警内容,设备名称+告警内容包含阈值信息可能opcae里没有带阈值信息那么就需要录入固定值可选Data10
alarmType = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data7)), // opcAeEventData.Severity 告警类型,子系统产生告警的类型,可能需要固定备注值
// ConfirmedTime = ack ? opcAeEventData.Time.DateTimeToUnixTimestamp() : null, //告警确认时间
// FixTime = isRecover ? opcAeEventData.Time.DateTimeToUnixTimestamp() : null, //解除告警时间
// LastTime = opcAeEventData.AlarmTime.DateTimeToUnixTimestamp(), //产生告警时间
// Status = isRecover ? "FIXED" : "UNFIXED", //告警状态
// AlarmLevel = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data8)), //opcAeEventData.Severity.ToString(), //告警等级,可能需要固定备注值
// SubSystemCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data9)), //子系统编码
// Type = "SUB_SYSTEM_ALARM", //默认填写字段
// ConfirmAccount = opcAeEventData.ActorID, //告警确认人
// ClearAccount = opcAeEventData.ActorID, //告警清除人
// ProcessInstruction = null //告警处理说明OPCAE不带有
// };
// alarmEntities.Add(alarmEntity);
// }
// else
// {
// Logger?.LogInformation($"找不到相关变量{sourceName}");
// }
// }
confirmedTime = ack ? opcAeEventData.Time.DateTimeToUnixTimestamp() : null, //告警确认时间
fixTime = isRecover ? opcAeEventData.Time : null, //解除告警时间
lastTime = opcAeEventData.AlarmTime, //产生告警时间
status = isRecover ? "FIXED" : "UNFIXED", //告警状态
alarmLevel = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data8)), //opcAeEventData.Severity.ToString(), //告警等级,可能需要固定备注值
subSystemCode = variableRuntime.GetPropertyValue(id, nameof(BusinessVariableProperty.Data9)), //子系统编码
type = "SUB_SYSTEM_ALARM", //默认填写字段
confirmAccount = opcAeEventData.ActorID, //告警确认人
clearAccount = opcAeEventData.ActorID, //告警清除人
processInstruction = null //告警处理说明OPCAE不带有
};
alarmEntities.Add(alarmEntity);
}
else
{
Logger?.LogInformation($"找不到相关变量{sourceName}");
}
}
// return alarmEntities;
// }
//}
return alarmEntities;
}
}
///// <summary>
///// 告警实体
///// </summary>
//public class KafkaAlarmEntity
//{
// /// <summary>
// /// 告警编码唯一 (非空)
// /// 示例:"8e8a118ac452fd04da8c26fa588a7cab"
// /// </summary>
// public string AlarmCode { get; set; }
/// <summary>
/// 告警实体
/// </summary>
public class KafkaAlarmEntity
{
/// <summary>
/// 告警编码唯一 (非空)
/// 示例:"8e8a118ac452fd04da8c26fa588a7cab"
/// </summary>
public string alarmCode { get; set; }
// /// <summary>
// /// 资源编码,唯一编码,需要按照映射表上传 (非空)
// /// 示例:"RS_A6K9MUSG19V"
// /// </summary>
// public string ResourceCode { get; set; }
/// <summary>
/// 资源编码,唯一编码,需要按照映射表上传 (非空)
/// 示例:"RS_A6K9MUSG19V"
/// </summary>
public string resourceCode { get; set; }
// /// <summary>
// /// 资源名称,需要按照映射表上传 (非空)
// /// 示例:"MB-A7"
// /// </summary>
// public string ResourceName { get; set; }
/// <summary>
/// 资源名称,需要按照映射表上传 (非空)
/// 示例:"MB-A7"
/// </summary>
public string resourceName { get; set; }
// /// <summary>
// /// 指标编码唯一,需要按照映射表上传 (非空)
// /// 示例:"ActivePowerPa"
// /// </summary>
// public string MetricCode { get; set; }
/// <summary>
/// 指标编码唯一,需要按照映射表上传 (非空)
/// 示例:"ActivePowerPa"
/// </summary>
public string metricCode { get; set; }
// /// <summary>
// /// 指标名称,需要按照映射表上传 (非空)
// /// 示例:"有功功率Pa"
// /// </summary>
// public string MetricName { get; set; }
/// <summary>
/// 指标名称,需要按照映射表上传 (非空)
/// 示例:"有功功率Pa"
/// </summary>
public string metricName { get; set; }
// /// <summary>
// /// 告警内容:设备名称+告警内容(包含阈值信息) (非空)
// /// 示例:"MB-A7有功功率Pa > 30"
// /// </summary>
// public string Content { get; set; }
/// <summary>
/// 告警内容:设备名称+告警内容(包含阈值信息) (非空)
/// 示例:"MB-A7有功功率Pa > 30"
/// </summary>
public string content { get; set; }
// /// <summary>
// /// 告警类型,子系统产生告警的类型 (非空)
// /// 示例:"0101" 表示高限报警
// /// </summary>
// public string AlarmType { get; set; }
/// <summary>
/// 告警类型,子系统产生告警的类型 (非空)
/// 示例:"0101" 表示高限报警
/// </summary>
public string alarmType { get; set; }
// /// <summary>
// /// 告警确认时间 (可空,时间戳)
// /// 示例1586152800000
// /// </summary>
// public long? ConfirmedTime { get; set; }
/// <summary>
/// 告警确认时间 (可空,时间戳)
/// 示例1586152800000
/// </summary>
public long? confirmedTime { get; set; }
// /// <summary>
// /// 解除告警时间 (可空,时间戳)
// /// 示例1586152800000
// /// </summary>
// public long? FixTime { get; set; }
/// <summary>
/// 解除告警时间 (可空,时间戳)
/// 示例1586152800000
/// </summary>
public DateTime? fixTime { get; set; }
// /// <summary>
// /// 产生告警时间 (非空,时间戳)
// /// 示例1586152800000
// /// </summary>
// public long LastTime { get; set; }
/// <summary>
/// 产生告警时间 (非空,时间戳)
/// 示例1586152800000
/// </summary>
public DateTime lastTime { get; set; }
// /// <summary>
// /// 告警状态 (非空)
// /// 可选值UNFIXED新增告警、FIXED解除告警
// /// </summary>
// public string Status { get; set; }
/// <summary>
/// 告警状态 (非空)
/// 可选值UNFIXED新增告警、FIXED解除告警
/// </summary>
public string status { get; set; }
// /// <summary>
// /// 告警等级,需要按照映射表上传 (非空)
// /// 示例:"1"
// /// </summary>
// public string AlarmLevel { get; set; }
/// <summary>
/// 告警等级,需要按照映射表上传 (非空)
/// 示例:"1"
/// </summary>
public string alarmLevel { get; set; }
// /// <summary>
// /// 子系统编码 (非空)
// /// 示例:"MS_NEW_PD_DCIM_001"
// /// </summary>
// public string SubSystemCode { get; set; }
/// <summary>
/// 子系统编码 (非空)
/// 示例:"MS_NEW_PD_DCIM_001"
/// </summary>
public string subSystemCode { get; set; }
// /// <summary>
// /// 默认填写字段 (非空)
// /// 固定值:"SUB_SYSTEM_ALARM"
// /// </summary>
// public string Type { get; set; }
/// <summary>
/// 默认填写字段 (非空)
/// 固定值:"SUB_SYSTEM_ALARM"
/// </summary>
public string type { get; set; }
// /// <summary>
// /// 告警确认人 (可空)
// /// 示例:"admin3"
// /// </summary>
// public string ConfirmAccount { get; set; }
/// <summary>
/// 告警确认人 (可空)
/// 示例:"admin3"
/// </summary>
public string confirmAccount { get; set; }
// /// <summary>
// /// 告警清除人 (可空)
// /// 示例:"admin"
// /// </summary>
// public string ClearAccount { get; set; }
/// <summary>
/// 告警清除人 (可空)
/// 示例:"admin"
/// </summary>
public string clearAccount { get; set; }
// /// <summary>
// /// 告警处理说明 (可空)
// /// 示例:"admin"
// /// </summary>
// public string ProcessInstruction { get; set; }
//}
/// <summary>
/// 告警处理说明 (可空)
/// 示例:"admin"
/// </summary>
public string processInstruction { get; set; }
}

View File

@@ -1,46 +1,46 @@
////------------------------------------------------------------------------------
////此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
//// 此代码版权除特别声明外的代码归作者本人Diego所有
//// 源代码使用协议遵循本仓库的开源协议及附加协议
//// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
//// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
//// 使用文档https://thingsgateway.cn/
//// QQ群605534569
//// ------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
// ------------------------------------------------------------------------------
//using ThingsGateway.Gateway.Application;
//using ThingsGateway.NewLife.Json.Extension;
//using ThingsGateway.Plugin.DB;
//using ThingsGateway.SqlSugar;
using ThingsGateway.Gateway.Application;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.Plugin.DB;
using ThingsGateway.SqlSugar;
//using TouchSocket.Core;
using TouchSocket.Core;
//public class TestSQL : DynamicSQLBase
//{
// public override Task DBInit(ISqlSugarClient db, CancellationToken cancellationToken)
// {
// db.DbMaintenance.CreateDatabase();
// db.CodeFirst.InitTables<ThingsGateway.Plugin.OpcAe.OpcAeEventData>();
// return Task.CompletedTask;
// }
public class TestSQL : DynamicSQLBase
{
public override Task DBInit(ISqlSugarClient db, CancellationToken cancellationToken)
{
db.DbMaintenance.CreateDatabase();
db.CodeFirst.InitTables<ThingsGateway.Plugin.OpcAe.OpcAeEventData>();
return Task.CompletedTask;
}
// public override async Task DBInsertable(ISqlSugarClient db, IEnumerable<object> datas, CancellationToken cancellationToken)
// {
// var pluginEventDatas = datas.Cast<PluginEventData>();
// var opcDatas = pluginEventDatas.Select(
// a =>
// {
// if (a.ObjectValue == null)
// {
// a.ObjectValue = a.Value.ToObject(Type.GetType(a.ValueType));
// }
// return a.ObjectValue is ThingsGateway.Plugin.OpcAe.OpcAeEventData opcData ? opcData : null;
// }
// ).Where(a => a != null).ToList();
// if (opcDatas.Count == 0)
// return;
// Logger?.Info(opcDatas.ToSystemTextJsonString());
public override async Task DBInsertable(ISqlSugarClient db, IEnumerable<object> datas, CancellationToken cancellationToken)
{
var pluginEventDatas = datas.Cast<PluginEventData>();
var opcDatas = pluginEventDatas.Select(
a =>
{
if (a.ObjectValue == null)
{
a.ObjectValue = a.Value.ToObject(Type.GetType(a.ValueType));
}
return a.ObjectValue is ThingsGateway.Plugin.OpcAe.OpcAeEventData opcData ? opcData : null;
}
).Where(a => a != null).ToList();
if (opcDatas.Count == 0)
return;
Logger?.Info(opcDatas.ToSystemTextJsonString());
// await db.Insertable(opcDatas).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
// }
//}
await db.Insertable(opcDatas).ExecuteCommandAsync(cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,49 @@
//------------------------------------------------------------------------------
//此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
// ------------------------------------------------------------------------------
using MQTTnet;
using MQTTnet.Server;
using Newtonsoft.Json.Linq;
using System.Text;
using ThingsGateway.Foundation;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.Plugin.Mqtt;
using TouchSocket.Core;
public class TestServerRpc : DynamicMqttServerRpcBase
{
public override async Task RPCInvokeAsync(ILog logMessage, InterceptingPublishEventArgs args, MqttServerProperty driverPropertys, MQTTnet.Server.MqttServer mqttServer, Func<string, Dictionary<string, Dictionary<string, JToken>>, ValueTask<Dictionary<string, Dictionary<string, IOperResult>>>> getRpcResult, CancellationToken cancellationToken)
{
if (driverPropertys.RpcWriteTopic.IsNullOrWhiteSpace()) return;
var t = string.Format(null, "{0}/+", driverPropertys.RpcWriteTopic);
if (MqttTopicFilterComparer.Compare(args.ApplicationMessage.Topic, t) != MqttTopicFilterCompareResult.IsMatch)
return;
var rpcDatas = Encoding.UTF8.GetString(args.ApplicationMessage.Payload).FromJsonNetString<Dictionary<string, Dictionary<string, JToken>>>();
if (rpcDatas == null)
return;
var mqttRpcResult = await getRpcResult(args.ClientId, rpcDatas).ConfigureAwait(false);
try
{
var variableMessage = new MqttApplicationMessageBuilder()
.WithTopic($"{args.ApplicationMessage.Topic}/Response")
.WithPayload(mqttRpcResult.ToSystemTextJsonString(driverPropertys.JsonFormattingIndented)).Build();
await mqttServer.InjectApplicationMessage(new InjectedMqttApplicationMessage(variableMessage), cancellationToken).ConfigureAwait(false);
}
catch
{
}
}
}

View File

@@ -3,43 +3,17 @@
<Import Project="..\Version.props" />
<ItemGroup Condition=" '$(SolutionName)' != 'ThingsGatewayRelease'">
<ItemGroup>
<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Application\ThingsGateway.Gateway.Application.csproj" />
<ProjectReference Include="..\Gateway\ThingsGateway.Gateway.Razor\ThingsGateway.Gateway.Razor.csproj" />
</ItemGroup>
<!--发布版-->
<Import Project="targets\Gateway.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " />
<Import Project="targets\Admin.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayRelease' " />
<Import Project="targets\PluginContext.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug' " />
<!--nuget包解压复制文件上下文动态加载-->
<Import Project="targets\PluginContext.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug' " />
<!--直接引用-->
<Import Project="targets\PluginDebug.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug' " />
<!--nuget包解压复制文件插件域隔离动态加载-->
<!--<Import Project="targets\Plugin.targets" />-->
<!--nuget包解压复制文件上下文动态加载Pro插件-->
<Import Project="targets\Pro2.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' OR '$(Configuration)' != 'Debug'" />
<!--直接引用Pro-->
<Import Project="targets\PluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
<Import Project="targets\PluginDebug.targets"/>
<Import Project="targets\ProPluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' == 'Debug'" />
<Import Project="targets\ProPluginDebug.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' "/>
<!--<Import Project="targets\Pro3.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' " />
<Import Project="targets\Pro5.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' " />-->
<!--<Import Project="targets\Pro6.targets" Condition=" '$(SolutionName)' == 'ThingsGatewayPro' AND '$(Configuration)' != 'Debug'" />-->
<!--nuget包解压复制文件上下文动态加载Pro插件-->
<Import Project="targets\Pro7.targets" Condition=" '$(SolutionName)' != 'ThingsGatewayPro' OR '$(Configuration)' != 'Debug'" />
<!--打包复制-->
<Import Project="targets\PluginPublish.targets" />
<PropertyGroup>
<GenerateDocumentationFile>false</GenerateDocumentationFile>