This commit is contained in:
ChenYi 2025-04-29 10:03:59 +08:00
commit cc8465ec77
29 changed files with 598 additions and 162 deletions

View File

@ -62,6 +62,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0.Docs", "0.Docs", "{D8346C
readme.md = readme.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiShe.CollectBus.Analyzers.Shared", "shared\JiShe.CollectBus.Analyzers.Shared\JiShe.CollectBus.Analyzers.Shared.csproj", "{DD68F314-BC66-5601-B094-B1A7BE93F4E0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JiShe.CollectBus.Analyzers", "modules\JiShe.CollectBus.Analyzers\JiShe.CollectBus.Analyzers.csproj", "{EB97C7BB-1E4A-CBA4-04C1-22DBF48A253A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -148,6 +152,14 @@ Global
{75B7D419-C261-577D-58D6-AA3ACED9129F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75B7D419-C261-577D-58D6-AA3ACED9129F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75B7D419-C261-577D-58D6-AA3ACED9129F}.Release|Any CPU.Build.0 = Release|Any CPU
{DD68F314-BC66-5601-B094-B1A7BE93F4E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD68F314-BC66-5601-B094-B1A7BE93F4E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD68F314-BC66-5601-B094-B1A7BE93F4E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD68F314-BC66-5601-B094-B1A7BE93F4E0}.Release|Any CPU.Build.0 = Release|Any CPU
{EB97C7BB-1E4A-CBA4-04C1-22DBF48A253A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB97C7BB-1E4A-CBA4-04C1-22DBF48A253A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB97C7BB-1E4A-CBA4-04C1-22DBF48A253A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB97C7BB-1E4A-CBA4-04C1-22DBF48A253A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -173,6 +185,8 @@ Global
{8A61DF78-069B-40B5-8811-614E2960443E} = {3C3F9DB2-EC97-4464-B49F-BF1A0C2B46DC}
{E27377CC-E2D3-4237-060F-96EA214D3129} = {3C3F9DB2-EC97-4464-B49F-BF1A0C2B46DC}
{75B7D419-C261-577D-58D6-AA3ACED9129F} = {3C3F9DB2-EC97-4464-B49F-BF1A0C2B46DC}
{DD68F314-BC66-5601-B094-B1A7BE93F4E0} = {EBF7C01F-9B4F-48E6-8418-2CBFDA51EB0B}
{EB97C7BB-1E4A-CBA4-04C1-22DBF48A253A} = {2E0FE301-34C3-4561-9CAE-C7A9E65AEE59}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4324B3B4-B60B-4E3C-91D8-59576B4E26DD}

View File

@ -0,0 +1,254 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace JiShe.CollectBus.IncrementalGenerator
{
/// <summary>
/// 复杂类型源生成器
/// </summary>
[Generator(LanguageNames.CSharp)]
public class ComplexTypeSourceAnalyzers : IIncrementalGenerator
{
private const string AttributeFullName = "JiShe.CollectBus.Analyzers.Shared.SourceAnalyzersAttribute";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
//Debugger.Launch();
context.RegisterPostInitializationOutput(ctx =>
{
ctx.AddSource("GeneratorInit.g.cs", "// Initialization Marker");
});
// 步骤1筛选带有 [GenerateAccessors] 的类
var classDeclarations = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: static (s, _) => IsClassWithAttribute(s),
transform: static (ctx, _) => GetClassDeclaration(ctx))
.Where(static c => c is not null);
// 步骤2合并编译信息
var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
context.RegisterSourceOutput(compilationAndClasses, (spc, source) =>
GenerateCode(source.Left, source.Right!, spc));
}
private static bool IsClassWithAttribute(SyntaxNode node) => node is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0;
private static ClassDeclarationSyntax GetClassDeclaration(GeneratorSyntaxContext context)
{
var classDecl = (ClassDeclarationSyntax)context.Node;
var attributeType = context.SemanticModel.Compilation.GetTypeByMetadataName(AttributeFullName);
foreach (var attribute in classDecl.AttributeLists.SelectMany(al => al.Attributes))
{
var symbol = context.SemanticModel.GetSymbolInfo(attribute).Symbol;
if (symbol is IMethodSymbol ctor &&
SymbolEqualityComparer.Default.Equals(ctor.ContainingType, attributeType))
{
return classDecl;
}
}
return null;
}
/// <summary>
/// 递归获取所有层级的属性
/// </summary>
/// <param name="classSymbol"></param>
/// <returns></returns>
private static IEnumerable<IPropertySymbol> GetAllPropertiesInHierarchy(INamedTypeSymbol classSymbol)
{
var currentSymbol = classSymbol;
while (currentSymbol != null)
{
foreach (var prop in currentSymbol.GetMembers().OfType<IPropertySymbol>())
{
yield return prop;
}
currentSymbol = currentSymbol.BaseType; // 向上遍历基类
}
}
private static void GenerateCode(
Compilation compilation,
IEnumerable<ClassDeclarationSyntax> classes,
SourceProductionContext context)
{
var processedTypes = new HashSet<ITypeSymbol>(SymbolEqualityComparer.Default);
if (!classes.Any())
{
context.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor("GEN002", "No Targets",
"No classes with [GenerateAccessors] found", "Debug", DiagnosticSeverity.Warning, true),
Location.None));
}
foreach (var classDecl in classes.Distinct())
{
var model = compilation.GetSemanticModel(classDecl.SyntaxTree);
var classSymbol = model.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;
if (classSymbol == null || !processedTypes.Add(classSymbol))
{
context.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor("GEN003", "Invalid Symbol",
$"Class symbol is null for {classDecl.Identifier.Text}", "Error", DiagnosticSeverity.Error, true),
Location.None));
continue;
}
context.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor(
"PA001",
"Generated Accessors",
$"Generating accessors for {classSymbol.Name}",
"Performance",
DiagnosticSeverity.Info,
true),
Location.None));
// 新增:输出继承链信息
context.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor("HIERARCHY", "Class Hierarchy",
$"Processing class: {classSymbol.Name}, BaseType: {classSymbol.BaseType?.Name}",
"Debug", DiagnosticSeverity.Info, true),
Location.None));
context.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor("PA002", "Class Found",
$"Processing class: {classSymbol.Name}", "Debug", DiagnosticSeverity.Warning, true),
Location.None));
var code = BuildAccessorsForType(classSymbol, compilation, processedTypes);
System.Diagnostics.Debug.WriteLine($"Generated code for {classSymbol.Name}:\n{code}"); // 调试输出
context.AddSource($"{classSymbol.Name}Extension.g.cs", code);
}
}
private static string BuildAccessorsForType(
INamedTypeSymbol classSymbol,
Compilation compilation,
HashSet<ITypeSymbol> processedTypes)
{
var code = new StringBuilder();
code.AppendLine("#pragma warning disable CS0419 // 禁用警告");
code.AppendLine("// Generated code for " + classSymbol.Name);
code.AppendLine("// <auto-generated/>");
code.AppendLine("#nullable enable");
code.AppendLine($"namespace {classSymbol.ContainingNamespace.ToDisplayString()};");
code.AppendLine();
code.AppendLine($"public static class {classSymbol.Name}Extension{GetGenericParams(classSymbol)}");
code.AppendLine("{");
//foreach (var prop in classSymbol.GetMembers().OfType<IPropertySymbol>())
//{
// if (prop.IsIndexer) continue;
// GeneratePropertyAccessors(prop, code, compilation, processedTypes);
//}
foreach (var prop in GetAllPropertiesInHierarchy(classSymbol))
{
if (prop.IsIndexer) continue;
GeneratePropertyAccessors(prop, code, compilation, processedTypes);
}
code.AppendLine("}");
return code.ToString();
}
//private static string GetGenericParams(INamedTypeSymbol symbol)
// => symbol.IsGenericType ? $"<{string.Join(", ", symbol.TypeParameters.Select(t => t.Name))}>" : "";
public static string GetGenericParams(INamedTypeSymbol symbol)
{
if (!symbol.IsGenericType) return "";
var parameters = symbol.TypeParameters.Select(t => t.Name);
return $"<{string.Join(", ", parameters)}>";
}
private static void GeneratePropertyAccessors(
IPropertySymbol prop,
StringBuilder code,
Compilation compilation,
HashSet<ITypeSymbol> processedTypes)
{
// 关键修复点1安全类型转换
if (prop.Type is not ITypeSymbol propType) return;
code.AppendLine($" // Processing property: {prop.Name}");
// 处理元组类型
if (propType is INamedTypeSymbol { IsTupleType: true } tupleType)
{
GenerateTupleAccessors(prop, tupleType, code);
}
else if (propType is INamedTypeSymbol namedType)
{
GenerateStandardAccessors(prop, namedType, code);
ProcessNestedType(namedType, compilation, processedTypes);
}
}
private static void GenerateTupleAccessors(IPropertySymbol prop, INamedTypeSymbol tupleType, StringBuilder code)
{
var elements = tupleType.TupleElements;
var parentType = prop.ContainingType.ToDisplayString();
for (int i = 0; i < elements.Length; i++)
{
var element = elements[i];
if (element.Type is not ITypeSymbol elementType) continue;
var elementName = element.CorrespondingTupleField?.Name ?? $"Item{i + 1}";
code.AppendLine($" public static {elementType.ToDisplayString()} Get{prop.Name}_{elementName}({parentType} obj) => obj.{prop.Name}.{elementName};");
if (prop.SetMethod != null)
{
var assignments = elements.Select((e, idx) =>
idx == i ? "value" : $"obj.{prop.Name}.{e.Name}");
code.AppendLine($" public static void Set{prop.Name}_{elementName}({parentType} obj, {elementType.ToDisplayString()} value) => obj.{prop.Name} = ({string.Join(", ", assignments)});");
}
}
}
private static void GenerateStandardAccessors(IPropertySymbol prop, INamedTypeSymbol propType, StringBuilder code)
{
var parentType = prop.ContainingType.ToDisplayString();
code.AppendLine($" public static {propType.ToDisplayString()} Get{prop.Name}({parentType} obj) => obj.{prop.Name};");
if (prop.SetMethod != null)
{
code.AppendLine($" public static void Set{prop.Name}({parentType} obj, {propType.ToDisplayString()} value) => obj.{prop.Name} = value;");
}
}
private static void ProcessNestedType(ITypeSymbol typeSymbol, Compilation compilation, HashSet<ITypeSymbol> processedTypes)
{
if (typeSymbol is not INamedTypeSymbol namedType) return;
if (!ShouldProcessNestedType(namedType)) return;
if (!processedTypes.Add(namedType)) return;
var code = BuildAccessorsForType(namedType, compilation, processedTypes);
}
private static bool ShouldProcessNestedType(INamedTypeSymbol symbol)
{
return symbol.DeclaredAccessibility == Accessibility.Public &&
!symbol.IsTupleType &&
!symbol.IsAnonymousType &&
!symbol.IsImplicitlyDeclared &&
!symbol.Name.StartsWith("<");
}
}
}

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IsRoslynComponent>true</IsRoslynComponent>
<NoPackageAnalysis>true</NoPackageAnalysis>
<ImportDirectoryBuildProps>false</ImportDirectoryBuildProps>
<BaseOutputPath>bin</BaseOutputPath>
<IncludeBuildOutput>false</IncludeBuildOutput>
<LangVersion>latest</LangVersion>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\shared\JiShe.CollectBus.Analyzers.Shared\JiShe.CollectBus.Analyzers.Shared.csproj" />
</ItemGroup>
</Project>

View File

@ -1,15 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Apache.IoTDB" Version="2.0.2" />
<PackageReference Include="Volo.Abp" Version="8.3.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\shared\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
<ProjectReference Include="..\..\shared\JiShe.CollectBus.Analyzers.Shared\JiShe.CollectBus.Analyzers.Shared.csproj" />
<ProjectReference Include="..\..\shared\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
<ProjectReference Include="..\..\modules\JiShe.CollectBus.Analyzers\JiShe.CollectBus.Analyzers.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup>
</Project>

View File

@ -1,9 +1,10 @@
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.Common.Attributes;
using JiShe.CollectBus.IoTDB.Attribute;
namespace JiShe.CollectBus.IoTDB.Model
{
/// <summary>
/// IoT实体基类此类适用于多个数据测点记录场景单个测点请使用子类 SingleMeasuring
/// IoT实体基类此类适用于多个数据测点记录场景单个测点请使用子类 SingleMeasuring,新增字段只能现有字段末尾添加,否则会导致数据写入失败。
/// </summary>
public abstract class IoTEntity
{

View File

@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Enums;
using JiShe.CollectBus.IoTDB.Provider;
namespace JiShe.CollectBus.IoTDB.Model
{
@ -13,6 +8,7 @@ namespace JiShe.CollectBus.IoTDB.Model
/// Table模型单项数据实体
/// </summary>
[EntityType(EntityTypeEnum.TableModel)]
[SourceAnalyzers]
public class TableModelSingleMeasuringEntity<T> : IoTEntity
{
/// <summary>

View File

@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Enums;
using JiShe.CollectBus.IoTDB.Provider;
namespace JiShe.CollectBus.IoTDB.Model
{
@ -13,6 +8,7 @@ namespace JiShe.CollectBus.IoTDB.Model
/// Tree模型单项数据实体
/// </summary>
[EntityType(EntityTypeEnum.TreeModel)]
[SourceAnalyzers]
public class TreeModelSingleMeasuringEntity<T> : IoTEntity
{
/// <summary>

View File

@ -26,7 +26,7 @@
/// <summary>
/// 连接池大小
/// </summary>
public int PoolSize { get; set; } = 2;
public int PoolSize { get; set; } = 8;
/// <summary>
/// 查询时每次查询的数据量默认1024

View File

@ -70,7 +70,7 @@ namespace JiShe.CollectBus.IoTDB.Provider
var result = await _sessionPool.InsertAlignedTabletAsync(tablet);
if (result != 0)
{
throw new Exception($"{nameof(SessionPoolAdapter)} Tree模型数据入库没有成功返回结果为{result}");
throw new Exception($"{nameof(SessionPoolAdapter)} Tree模型数据入库没有成功返回结果为{result}请检查IoTEntity继承子类属性索引是否有变动。");
}
//await CloseAsync();
return result;

View File

@ -68,7 +68,7 @@ namespace JiShe.CollectBus.IoTDB.Provider
var result = await _sessionPool.InsertAsync(tablet);
if (result != 0)
{
throw new Exception($"{nameof(TableSessionPoolAdapter)} table模型数据入库没有成功返回结果为{result}");
throw new Exception($"{nameof(TableSessionPoolAdapter)} table模型数据入库没有成功返回结果为{result}请检查IoTEntity继承子类属性索引是否有变动。");
}
//await CloseAsync();

View File

@ -124,7 +124,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
/// 水表数据采集
/// </summary>
/// <returns></returns>
Task WatermeterScheduledMeterAutoReading();
Task WatermeterScheduledMeterAutoReadding();
#endregion

View File

@ -66,12 +66,17 @@ public class CollectBusApplicationModule : AbpModule
.ToList();
foreach (var type in types) await context.AddBackgroundWorkerAsync(type);
Task.Run(() =>
{
//默认初始化表计信息
var dbContext = context.ServiceProvider.GetRequiredService<EnergySystemScheduledMeterReadingService>();
dbContext.InitAmmeterCacheData();
//await dbContext.InitWatermeterCacheData();
}).ConfigureAwait(false);
//Task.Run(() =>
//{
// //默认初始化表计信息
// var dbContext = context.ServiceProvider.GetRequiredService<EnergySystemScheduledMeterReadingService>();
// dbContext.InitAmmeterCacheData();
// //await dbContext.InitWatermeterCacheData();
//}).ConfigureAwait(false);
//默认初始化表计信息
var dbContext = context.ServiceProvider.GetRequiredService<EnergySystemScheduledMeterReadingService>();
_= dbContext.InitAmmeterCacheData();
}
}

View File

@ -23,13 +23,14 @@
<PackageReference Include="TouchSocket.Hosting" Version="3.1.0" />
<PackageReference Include="Volo.Abp.EventBus.Kafka" Version="8.3.3" />
<ProjectReference Include="..\..\protocols\JiShe.CollectBus.Protocol\JiShe.CollectBus.Protocol.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.Application.Contracts\JiShe.CollectBus.Application.Contracts.csproj" />
<ProjectReference Include="..\..\modules\JiShe.CollectBus.Cassandra\JiShe.CollectBus.Cassandra.csproj" />
<ProjectReference Include="..\..\modules\JiShe.CollectBus.FreeRedis\JiShe.CollectBus.FreeRedis.csproj" />
<ProjectReference Include="..\..\modules\JiShe.CollectBus.Kafka\JiShe.CollectBus.Kafka.csproj" />
<ProjectReference Include="..\..\modules\JiShe.CollectBus.MongoDB\JiShe.CollectBus.MongoDB.csproj" />
</ItemGroup>
</Project>

View File

@ -66,6 +66,7 @@ public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaS
IssuedMessageHexString = "messageHexString",
Timestamps = testTime// DateTimeOffset.UtcNow.ToUnixTimeNanoseconds()//testTime.GetDateTimeOffset().ToUnixTimeNanoseconds(),
};
//ElectricityMeterTreeModelExtension.GetCurrent()
await _iotDBProvider.InsertAsync(meter);
}

View File

@ -286,52 +286,51 @@ namespace JiShe.CollectBus.ScheduledMeterReading
public virtual async Task InitAmmeterCacheData(string gatherCode = "")
{
//此处代码不要删除
//#if DEBUG
// var timeDensity = "15";
// var redisCacheMeterInfoHashKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoHashKey, SystemType, "JiSheCollectBus2", MeterTypeEnum.Ammeter, timeDensity)}";
// var redisCacheMeterInfoSetIndexKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoSetIndexKey, SystemType, "JiSheCollectBus2", MeterTypeEnum.Ammeter, timeDensity)}";
// var redisCacheMeterInfoZSetScoresIndexKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoZSetScoresIndexKey, SystemType, "JiSheCollectBus2", MeterTypeEnum.Ammeter, timeDensity)}";
#if DEBUG
var timeDensity = "15";
var redisCacheMeterInfoHashKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoHashKey, SystemType, "JiSheCollectBus2", MeterTypeEnum.Ammeter, timeDensity)}";
var redisCacheMeterInfoSetIndexKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoSetIndexKey, SystemType, "JiSheCollectBus2", MeterTypeEnum.Ammeter, timeDensity)}";
var redisCacheMeterInfoZSetScoresIndexKeyTemp = $"{string.Format(RedisConst.CacheMeterInfoZSetScoresIndexKey, SystemType, "JiSheCollectBus2", MeterTypeEnum.Ammeter, timeDensity)}";
// List<AmmeterInfo> meterInfos = new List<AmmeterInfo>();
// List<string> focusAddressDataLista = new List<string>();
// var timer1 = Stopwatch.StartNew();
List<AmmeterInfo> meterInfos = new List<AmmeterInfo>();
List<string> focusAddressDataLista = new List<string>();
var timer1 = Stopwatch.StartNew();
// var allIds = new HashSet<string>();
// decimal? score = null;
// string member = null;
var allIds = new HashSet<string>();
decimal? score = null;
string member = null;
// while (true)
// {
// var page = await _redisDataCacheService.GetAllPagedData<AmmeterInfo>(
// redisCacheMeterInfoHashKeyTemp,
// redisCacheMeterInfoZSetScoresIndexKeyTemp,
// pageSize: 1000,
// lastScore: score,
// lastMember: member);
while (true)
{
var page = await _redisDataCacheService.GetAllPagedData<AmmeterInfo>(
redisCacheMeterInfoHashKeyTemp,
redisCacheMeterInfoZSetScoresIndexKeyTemp,
pageSize: 1000,
lastScore: score,
lastMember: member);
// meterInfos.AddRange(page.Items);
// focusAddressDataLista.AddRange(page.Items.Select(d => d.FocusAddress));
// foreach (var item in page.Items)
// {
// if (!allIds.Add(item.MemberId))
// {
// _logger.LogError($"{item.MemberId}Duplicate data found!");
// }
// }
// if (!page.HasNext) break;
// score = page.NextScore;
// member = page.NextMember;
// }
meterInfos.AddRange(page.Items);
focusAddressDataLista.AddRange(page.Items.Select(d => d.FocusAddress));
foreach (var item in page.Items)
{
if (!allIds.Add(item.MemberId))
{
_logger.LogError($"{item.MemberId}Duplicate data found!");
}
}
if (!page.HasNext) break;
score = page.NextScore;
member = page.NextMember;
}
// timer1.Stop();
// _logger.LogError($"读取数据总共花费时间{timer1.ElapsedMilliseconds}毫秒");
// DeviceGroupBalanceControl.InitializeCache(focusAddressDataLista, _kafkaOptions.NumPartitions);
// return;
//#else
// var meterInfos = await GetAmmeterInfoList(gatherCode);
//#endif
var meterInfos = await GetAmmeterInfoList(gatherCode);
timer1.Stop();
_logger.LogError($"读取数据总共花费时间{timer1.ElapsedMilliseconds}毫秒");
DeviceGroupBalanceControl.InitializeCache(focusAddressDataLista, _kafkaOptions.NumPartitions);
return;
#else
var meterInfos = await GetAmmeterInfoList(gatherCode);
#endif
if (meterInfos == null || meterInfos.Count <= 0)
{
throw new NullReferenceException($"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据时,电表数据为空");
@ -710,7 +709,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
itemCode: tempItem,
subItemCode: null,
pendingCopyReadTime: currentTime,
creationTime: currentTime);
creationTime: currentTime,
packetType: (TelemetryPacketTypeEnum)timeDensity);
taskList.Add(meterReadingRecords);
}
@ -792,7 +792,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
itemCode: itemCode,
subItemCode: subItemCode,
pendingCopyReadTime: currentTime,
creationTime: currentTime);
creationTime: currentTime,
packetType: TelemetryPacketTypeEnum.AmmeterAutomaticVerificationTime);
taskList.Add(meterReadingRecords);
if (taskList == null || taskList.Count <= 0)
@ -856,7 +857,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有找到对应的协议组件,-105");
return;
}
foreach (var item in DayFreezeCodes)
{
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
@ -873,10 +874,11 @@ namespace JiShe.CollectBus.ScheduledMeterReading
itemCode: item,
subItemCode: null,
pendingCopyReadTime: currentTime,
creationTime: currentTime);
creationTime: currentTime,
packetType: TelemetryPacketTypeEnum.AmmeterDayFreeze);
taskList.Add(meterReadingRecords);
}
if (taskList == null || taskList.Count <= 0)
{
@ -896,7 +898,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
_ = KafkaProducerIssuedMessageAction(ProtocolConst.AmmeterSubscriberWorkerOtherIssuedEventName, data, groupIndex);
}
);
}
catch (Exception)
{
@ -955,7 +957,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
itemCode: item,
subItemCode: null,
pendingCopyReadTime: currentTime,
creationTime: currentTime);
creationTime: currentTime,
packetType: TelemetryPacketTypeEnum.AmmeterMonthFreeze);
taskList.Add(meterReadingRecords);
}
@ -1165,7 +1168,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
/// 水表数据采集
/// </summary>
/// <returns></returns>
public virtual async Task WatermeterScheduledMeterAutoReading()
public virtual async Task WatermeterScheduledMeterAutoReadding()
{
//获取缓存中的水表信息
int timeDensity = 60;//水表目前只有一个采集频率 60分钟
@ -1197,7 +1200,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
Conditions = conditions,
});
_logger.LogInformation($"{nameof(WatermeterScheduledMeterAutoReading)} {timeDensity}分钟采集水表数据处理完成");
_logger.LogInformation($"{nameof(WatermeterScheduledMeterAutoReadding)} {timeDensity}分钟采集水表数据处理完成");
}
/// <summary>
@ -1282,7 +1285,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
DeviceId = $"{watermeter.MeterId}",
Timestamps = DateTimeOffset.Now.ToUnixTimeNanoseconds(),
DatabaseBusiID = watermeter.DatabaseBusiID,
PendingCopyReadTime = timestamps,
PacketType = (int)TelemetryPacketTypeEnum.WatermeterAutoReadding,
PendingCopyReadTime = timestamps,
CreationTime = currentTime,
MeterAddress = watermeter.MeterAddress,
AFN = builderResponse.AFn,
@ -1366,7 +1370,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
itemCode: itemCode,
subItemCode: null,
pendingCopyReadTime: currentTime,
creationTime: currentTime);
creationTime: currentTime,
packetType: TelemetryPacketTypeEnum.TerminalVersion);
taskList.Add(meterReadingRecords);
if (taskList == null || taskList.Count <= 0)
@ -1444,7 +1449,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
itemCode: itemCode,
subItemCode: null,
pendingCopyReadTime: currentTime,
creationTime: currentTime);
creationTime: currentTime,
packetType: TelemetryPacketTypeEnum.TelematicsModule);
taskList.Add(meterReadingRecords);
if (taskList == null || taskList.Count <= 0)
@ -1628,8 +1634,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
/// <param name="subItemCode">端到端采集项编码</param>
/// <param name="pendingCopyReadTime">待采集时间,定时采集频率才是特殊情况,其他默认当前时间戳</param>
/// <param name="creationTime">数据创建时间戳</param>
/// <param name="packetType">数据包类型</param>
/// <returns></returns>
protected MeterReadingTelemetryPacketInfo CreateAmmeterPacketInfo(AmmeterInfo ammeterInfo, long timestamps, ProtocolBuildResponse builderResponse, string itemCode, string subItemCode, DateTime pendingCopyReadTime, DateTime creationTime)
protected MeterReadingTelemetryPacketInfo CreateAmmeterPacketInfo(AmmeterInfo ammeterInfo, long timestamps, ProtocolBuildResponse builderResponse, string itemCode, string subItemCode, DateTime pendingCopyReadTime, DateTime creationTime, TelemetryPacketTypeEnum packetType)
{
string taskMark = CommonHelper.GetTaskMark(builderResponse.AFn, builderResponse.Fn, ammeterInfo.MeteringCode, builderResponse.MSA, builderResponse.Seq);
return new MeterReadingTelemetryPacketInfo()
@ -1643,10 +1650,13 @@ namespace JiShe.CollectBus.ScheduledMeterReading
PendingCopyReadTime = pendingCopyReadTime,
CreationTime = creationTime,
MeterAddress = ammeterInfo.AmmerterAddress,
PacketType = (int)packetType,
AFN = builderResponse.AFn,
Fn = builderResponse.Fn,
Seq = builderResponse.Seq,
MSA = builderResponse.MSA,
FocusId = ammeterInfo.FocusId,
FocusAddress = ammeterInfo.FocusAddress,
ItemCode = itemCode,
SubItemCode = subItemCode,
TaskMark = taskMark,

View File

@ -35,6 +35,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
//[Route($"/energy/app/scheduled")]
public class EnergySystemScheduledMeterReadingService : BasicScheduledMeterReadingService
{
string systemType = string.Empty;
string serverTagName = string.Empty;
private readonly ILogger<BasicScheduledMeterReadingService> _logger;
private readonly IIoTDbProvider _dbProvider;
@ -59,12 +60,13 @@ namespace JiShe.CollectBus.ScheduledMeterReading
applicationOptions)
{
serverTagName = applicationOptions.Value.ServerTagName;
systemType = applicationOptions.Value.SystemType;
_dbProvider = dbProvider;
_logger = logger;
_protocolService = protocolService;
}
public sealed override string SystemType => SystemTypeConst.Energy;
public sealed override string SystemType => systemType;
public sealed override string ServerTagName => serverTagName;

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Enums;
using JiShe.CollectBus.IoTDB.Model;
@ -10,6 +6,7 @@ using JiShe.CollectBus.IoTDB.Model;
namespace JiShe.CollectBus.Ammeters
{
[EntityType(EntityTypeEnum.TableModel)]
[SourceAnalyzers]
public class ElectricityMeter : IoTEntity
{
[ATTRIBUTEColumn]

View File

@ -1,10 +1,12 @@
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Enums;
using JiShe.CollectBus.IoTDB.Model;
namespace JiShe.CollectBus.Ammeters
{
[EntityType(EntityTypeEnum.TreeModel)]
[SourceAnalyzers]
public class ElectricityMeterTreeModel : IoTEntity
{
[ATTRIBUTEColumn]

View File

@ -1,16 +1,8 @@
using JiShe.CollectBus.Common.Encrypt;
using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.Analyzers.Shared;
using JiShe.CollectBus.IoTDB.Attribute;
using JiShe.CollectBus.IoTDB.Enums;
using JiShe.CollectBus.IoTDB.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
namespace JiShe.CollectBus.IotSystems.MeterReadingRecords
{
@ -18,6 +10,7 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords
/// 抄读任务数据
/// </summary>
[EntityType(EntityTypeEnum.TableModel)]
[SourceAnalyzers]
public class MeterReadingTelemetryPacketInfo : IoTEntity
{
/// <summary>
@ -25,7 +18,13 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords
/// </summary>
[FIELDColumn]
public string ScoreValue { get; set; }
/// <summary>
/// 数据包类型
/// </summary>
[FIELDColumn]
public int PacketType { get; set; }
/// <summary>
/// 是否手动操作
/// </summary>
@ -62,12 +61,6 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords
/// </summary>
[FIELDColumn]
public string FocusAddress { get; set; }
/// <summary>
/// 表Id
/// </summary>
[FIELDColumn]
public int MeterId { get; set; }
/// <summary>
/// 表地址
@ -96,6 +89,7 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords
/// <summary>
/// 抄读计量点
/// </summary>
[FIELDColumn]
public int Pn { get; set; }
/// <summary>
@ -114,6 +108,7 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords
/// <summary>
/// 帧序列域 SEQ
/// </summary>
[FIELDColumn]
public int Seq { get; set; }
/// <summary>
@ -132,7 +127,7 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords
/// 发送次数
/// </summary>
[FIELDColumn]
public int SendNum { get; set; }=0;
public int? SendNum { get; set; }
/// <summary>
/// 下次发送时间

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>JiShe.CollectBus</RootNamespace>
@ -23,9 +23,12 @@
<ItemGroup>
<ProjectReference Include="..\..\modules\JiShe.CollectBus.FreeSql\JiShe.CollectBus.FreeSql.csproj" />
<ProjectReference Include="..\..\modules\JiShe.CollectBus.IoTDB\JiShe.CollectBus.IoTDB.csproj" />
<ProjectReference Include="..\..\shared\JiShe.CollectBus.Analyzers.Shared\JiShe.CollectBus.Analyzers.Shared.csproj" />
<ProjectReference Include="..\..\shared\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
<ProjectReference Include="..\..\shared\JiShe.CollectBus.Domain.Shared\JiShe.CollectBus.Domain.Shared.csproj" />
</ItemGroup>
<ProjectReference Include="..\..\modules\JiShe.CollectBus.Analyzers\JiShe.CollectBus.Analyzers.csproj"
OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Emailing" Version="8.3.3" />

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace JiShe.CollectBus.Analyzers
{
public interface ISourceAnalyzersProvider<T>
{
/// <summary>
/// 获取属性值
/// </summary>
/// <param name="entity"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
object GetPropertyValue(T entity, string propertyName);
/// <summary>
/// 设置属性值
/// </summary>
/// <param name="entity"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
void SetPropertyValue(T entity, string propertyName, object value);
/// <summary>
/// 判断是否是元组属性
/// </summary>
/// <param name="propertyName"></param>
/// <returns></returns>
bool IsTupleProperty(string propertyName);
/// <summary>
/// 获取元组属性值
/// </summary>
/// <param name="entity"></param>
/// <param name="tuplePropertyName"></param>
/// <returns></returns>
(object Item1, object Item2) GetTupleParts(T entity, string tuplePropertyName);
}
}

View File

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,12 @@
using System;
namespace JiShe.CollectBus.Analyzers.Shared
{
/// <summary>
/// 标记需要生成源码的类
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class SourceAnalyzersAttribute : Attribute
{
}
}

View File

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Common.Enums
{
/// <summary>
/// 遥测数据包类型枚举
/// </summary>
public enum TelemetryPacketTypeEnum
{
/// <summary>
/// 1分钟密度
/// </summary>
[Description("1分钟密度")]
AmmeterOneMinute = 1,
/// <summary>
/// 5分钟密度
/// </summary>
[Description("5分钟密度")]
AmmeterMeterFiveMinute = 5,
/// <summary>
/// 15分钟密度
/// </summary>
[Description("15分钟密度")]
AmmeterFifteenMinute = 15,
/// <summary>
/// 自动校时
/// </summary>
[Description("自动校时")]
AmmeterAutomaticVerificationTime = 16,
/// <summary>
/// 日冻结
/// </summary>
[Description("日冻结")]
AmmeterDayFreeze = 17,
/// <summary>
/// 月冻结
/// </summary>
[Description("月冻结")]
AmmeterMonthFreeze = 18,
/// <summary>
/// 自动阀控
/// </summary>
[Description("自动阀控")]
AmmeterAutoValveControl = 19,
/// <summary>
/// 集中器终端版本
/// </summary>
[Description("集中器终端版本")]
TerminalVersion = 20,
/// <summary>
/// 集中器通信模块SIM
/// </summary>
[Description("集中器通信模块SIM")]
TelematicsModule = 21,
/// <summary>
/// 水表抄读
/// </summary>
[Description("水表抄读")]
WatermeterAutoReadding = 22,
}
}

View File

@ -17,7 +17,7 @@
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0" />
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
@ -25,8 +25,7 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Volo.Abp.Core" Version="8.3.3" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="8.3.3" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="8.3.3" />
</ItemGroup>
</Project>

View File

@ -8,12 +8,12 @@
/// <summary>
/// 服务器标识
/// </summary>
public required string ServerTagName { get; set; }
public string ServerTagName { get; set; }
/// <summary>
/// 系统类型
/// </summary>
public required string SystemType { get; set; }
public string SystemType { get; set; }
/// <summary>
/// 首次采集时间
@ -23,31 +23,31 @@
/// <summary>
/// 自动验证时间
/// </summary>
public required string AutomaticVerificationTime { get; set; }
public string AutomaticVerificationTime { get; set; }
/// <summary>
/// 自动获取终端版时间
/// </summary>
public required string AutomaticTerminalVersionTime { get; set; }
public string AutomaticTerminalVersionTime { get; set; }
/// <summary>
/// 自动获取远程通信模块(SIM)版本时间
/// </summary>
public required string AutomaticTelematicsModuleTime { get; set; }
public string AutomaticTelematicsModuleTime { get; set; }
/// <summary>
/// 日冻结抄读时间
/// </summary>
public required string AutomaticDayFreezeTime { get; set; }
public string AutomaticDayFreezeTime { get; set; }
/// <summary>
/// 月冻结抄读时间
/// </summary>
public required string AutomaticMonthFreezeTime { get; set; }
public string AutomaticMonthFreezeTime { get; set; }
/// <summary>
/// 默认协议插件
/// </summary>
public required string DefaultProtocolPlugin { get; set; }
public string DefaultProtocolPlugin { get; set; }
}
}

View File

@ -1,38 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>JiShe.CollectBus</RootNamespace>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>JiShe.CollectBus</RootNamespace>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Domain.Shared" Version="8.3.3" />
<PackageReference Include="Volo.Abp.Validation" Version="8.3.3" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Domain.Shared" Version="8.3.3" />
<PackageReference Include="Volo.Abp.Validation" Version="8.3.3" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.4" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.4" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\CollectBus\*.json" />
<Compile Remove="Caches\**" />
<Content Remove="Localization\CollectBus\*.json" />
<EmbeddedResource Remove="Caches\**" />
<None Remove="Caches\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\CollectBus\*.json" />
<Compile Remove="Caches\**" />
<Content Remove="Localization\CollectBus\*.json" />
<EmbeddedResource Remove="Caches\**" />
<None Remove="Caches\**" />
</ItemGroup>
<ItemGroup>
<None Remove="FodyWeavers.xml" />
<None Remove="JiShe.CollectBus.Domain.Shared.abppkg" />
</ItemGroup>
<ItemGroup>
<None Remove="FodyWeavers.xml" />
<None Remove="JiShe.CollectBus.Domain.Shared.abppkg" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JiShe.CollectBus.Common\JiShe.CollectBus.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
</PropertyGroup>
<ItemGroup>
<Compile Remove="logs\**" />
@ -55,9 +55,9 @@
<ItemGroup>
<ProjectReference Include="..\..\modules\JiShe.CollectBus.MongoDB\JiShe.CollectBus.MongoDB.csproj" />
<ProjectReference Include="..\..\services\JiShe.CollectBus.Application.Contracts\JiShe.CollectBus.Application.Contracts.csproj" />
<ProjectReference Include="..\..\services\JiShe.CollectBus.Application\JiShe.CollectBus.Application.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.HttpApi\JiShe.CollectBus.HttpApi.csproj" />
</ItemGroup>
<ProjectReference Include="..\..\services\JiShe.CollectBus.Application\JiShe.CollectBus.Application.csproj" />
<ProjectReference Include="..\JiShe.CollectBus.HttpApi\JiShe.CollectBus.HttpApi.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">

View File

@ -5,7 +5,7 @@
"Serilog.Sinks.File"
],
"MinimumLevel": {
"Default": "Warning",
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Volo.Abp": "Warning",
@ -87,7 +87,7 @@
"UserName": "root",
"Password": "root",
"ClusterList": [ "192.168.1.9:6667" ],
"PoolSize": 2,
"PoolSize": 32,
"DataBaseName": "energy",
"OpenDebugMode": true,
"UseTableSessionPoolByDefault": false
@ -142,9 +142,9 @@
}
},
"ServerApplicationOptions": {
"ServerTagName": "JiSheCollectBus100",
"SystemType": null,
"FirstCollectionTime": "2025-04-22 16:07:00",
"ServerTagName": "JiSheCollectBus4",
"SystemType": "Energy",
"FirstCollectionTime": "2025-04-28 15:07:00",
"AutomaticVerificationTime": "16:07:00",
"AutomaticTerminalVersionTime": "17:07:00",
"AutomaticTelematicsModuleTime": "17:30:00",