diff --git a/JiShe.CollectBus.sln b/JiShe.CollectBus.sln index 1ecb18c..f02dd6e 100644 --- a/JiShe.CollectBus.sln +++ b/JiShe.CollectBus.sln @@ -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} diff --git a/modules/JiShe.CollectBus.Analyzers/ComplexTypeSourceAnalyzers.cs b/modules/JiShe.CollectBus.Analyzers/ComplexTypeSourceAnalyzers.cs new file mode 100644 index 0000000..20951e5 --- /dev/null +++ b/modules/JiShe.CollectBus.Analyzers/ComplexTypeSourceAnalyzers.cs @@ -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 +{ + /// + /// 复杂类型源生成器 + /// + [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; + } + + /// + /// 递归获取所有层级的属性 + /// + /// + /// + private static IEnumerable GetAllPropertiesInHierarchy(INamedTypeSymbol classSymbol) + { + var currentSymbol = classSymbol; + while (currentSymbol != null) + { + foreach (var prop in currentSymbol.GetMembers().OfType()) + { + yield return prop; + } + currentSymbol = currentSymbol.BaseType; // 向上遍历基类 + } + } + + private static void GenerateCode( + Compilation compilation, + IEnumerable classes, + SourceProductionContext context) + { + var processedTypes = new HashSet(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 processedTypes) + { + var code = new StringBuilder(); + code.AppendLine("#pragma warning disable CS0419 // 禁用警告"); + code.AppendLine("// Generated code for " + classSymbol.Name); + code.AppendLine("// "); + 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()) + //{ + // 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 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 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("<"); + } + } +} \ No newline at end of file diff --git a/modules/JiShe.CollectBus.Analyzers/JiShe.CollectBus.Analyzers.csproj b/modules/JiShe.CollectBus.Analyzers/JiShe.CollectBus.Analyzers.csproj new file mode 100644 index 0000000..7e7fab1 --- /dev/null +++ b/modules/JiShe.CollectBus.Analyzers/JiShe.CollectBus.Analyzers.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0 + true + true + false + bin + false + latest + true + true + + + + + + + + + diff --git a/modules/JiShe.CollectBus.IoTDB/JiShe.CollectBus.IoTDB.csproj b/modules/JiShe.CollectBus.IoTDB/JiShe.CollectBus.IoTDB.csproj index 8cc4b33..3911399 100644 --- a/modules/JiShe.CollectBus.IoTDB/JiShe.CollectBus.IoTDB.csproj +++ b/modules/JiShe.CollectBus.IoTDB/JiShe.CollectBus.IoTDB.csproj @@ -1,15 +1,20 @@  - - net8.0 - enable - enable - + + net8.0 + enable + enable + - + + + + + diff --git a/modules/JiShe.CollectBus.IoTDB/Model/IoTEntity.cs b/modules/JiShe.CollectBus.IoTDB/Model/IoTEntity.cs index a079bd4..48bc248 100644 --- a/modules/JiShe.CollectBus.IoTDB/Model/IoTEntity.cs +++ b/modules/JiShe.CollectBus.IoTDB/Model/IoTEntity.cs @@ -1,9 +1,10 @@ -using JiShe.CollectBus.IoTDB.Attribute; +using JiShe.CollectBus.Common.Attributes; +using JiShe.CollectBus.IoTDB.Attribute; namespace JiShe.CollectBus.IoTDB.Model { /// - /// IoT实体基类,此类适用于多个数据测点记录场景,单个测点请使用子类 SingleMeasuring + /// IoT实体基类,此类适用于多个数据测点记录场景,单个测点请使用子类 SingleMeasuring,新增字段只能现有字段末尾添加,否则会导致数据写入失败。 /// public abstract class IoTEntity { diff --git a/modules/JiShe.CollectBus.IoTDB/Model/TableModelSingleMeasuringEntity.cs b/modules/JiShe.CollectBus.IoTDB/Model/TableModelSingleMeasuringEntity.cs index 4308dae..966f226 100644 --- a/modules/JiShe.CollectBus.IoTDB/Model/TableModelSingleMeasuringEntity.cs +++ b/modules/JiShe.CollectBus.IoTDB/Model/TableModelSingleMeasuringEntity.cs @@ -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模型单项数据实体 /// [EntityType(EntityTypeEnum.TableModel)] + [SourceAnalyzers] public class TableModelSingleMeasuringEntity : IoTEntity { /// diff --git a/modules/JiShe.CollectBus.IoTDB/Model/TreeModelSingleMeasuringEntity.cs b/modules/JiShe.CollectBus.IoTDB/Model/TreeModelSingleMeasuringEntity.cs index 9b3609c..719c3c3 100644 --- a/modules/JiShe.CollectBus.IoTDB/Model/TreeModelSingleMeasuringEntity.cs +++ b/modules/JiShe.CollectBus.IoTDB/Model/TreeModelSingleMeasuringEntity.cs @@ -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模型单项数据实体 /// [EntityType(EntityTypeEnum.TreeModel)] + [SourceAnalyzers] public class TreeModelSingleMeasuringEntity : IoTEntity { /// diff --git a/modules/JiShe.CollectBus.IoTDB/Options/IoTDBOptions.cs b/modules/JiShe.CollectBus.IoTDB/Options/IoTDBOptions.cs index 251e48b..68b2770 100644 --- a/modules/JiShe.CollectBus.IoTDB/Options/IoTDBOptions.cs +++ b/modules/JiShe.CollectBus.IoTDB/Options/IoTDBOptions.cs @@ -26,7 +26,7 @@ /// /// 连接池大小 /// - public int PoolSize { get; set; } = 2; + public int PoolSize { get; set; } = 8; /// /// 查询时,每次查询的数据量,默认1024 diff --git a/modules/JiShe.CollectBus.IoTDB/Provider/SessionPoolAdapter.cs b/modules/JiShe.CollectBus.IoTDB/Provider/SessionPoolAdapter.cs index ee71cf1..26ea4c7 100644 --- a/modules/JiShe.CollectBus.IoTDB/Provider/SessionPoolAdapter.cs +++ b/modules/JiShe.CollectBus.IoTDB/Provider/SessionPoolAdapter.cs @@ -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; diff --git a/modules/JiShe.CollectBus.IoTDB/Provider/TableSessionPoolAdapter.cs b/modules/JiShe.CollectBus.IoTDB/Provider/TableSessionPoolAdapter.cs index dc4f0ee..8edb112 100644 --- a/modules/JiShe.CollectBus.IoTDB/Provider/TableSessionPoolAdapter.cs +++ b/modules/JiShe.CollectBus.IoTDB/Provider/TableSessionPoolAdapter.cs @@ -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(); diff --git a/services/JiShe.CollectBus.Application.Contracts/ScheduledMeterReading/IScheduledMeterReadingService.cs b/services/JiShe.CollectBus.Application.Contracts/ScheduledMeterReading/IScheduledMeterReadingService.cs index 1a06897..4dde0be 100644 --- a/services/JiShe.CollectBus.Application.Contracts/ScheduledMeterReading/IScheduledMeterReadingService.cs +++ b/services/JiShe.CollectBus.Application.Contracts/ScheduledMeterReading/IScheduledMeterReadingService.cs @@ -124,7 +124,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading /// 水表数据采集 /// /// - Task WatermeterScheduledMeterAutoReading(); + Task WatermeterScheduledMeterAutoReadding(); #endregion diff --git a/services/JiShe.CollectBus.Application/CollectBusApplicationModule.cs b/services/JiShe.CollectBus.Application/CollectBusApplicationModule.cs index ce2e5aa..8b3da38 100644 --- a/services/JiShe.CollectBus.Application/CollectBusApplicationModule.cs +++ b/services/JiShe.CollectBus.Application/CollectBusApplicationModule.cs @@ -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(); - dbContext.InitAmmeterCacheData(); - //await dbContext.InitWatermeterCacheData(); - }).ConfigureAwait(false); + //Task.Run(() => + //{ + // //默认初始化表计信息 + // var dbContext = context.ServiceProvider.GetRequiredService(); + // dbContext.InitAmmeterCacheData(); + // //await dbContext.InitWatermeterCacheData(); + //}).ConfigureAwait(false); + + + //默认初始化表计信息 + var dbContext = context.ServiceProvider.GetRequiredService(); + _= dbContext.InitAmmeterCacheData(); } } \ No newline at end of file diff --git a/services/JiShe.CollectBus.Application/JiShe.CollectBus.Application.csproj b/services/JiShe.CollectBus.Application/JiShe.CollectBus.Application.csproj index aefe5e4..b9d899c 100644 --- a/services/JiShe.CollectBus.Application/JiShe.CollectBus.Application.csproj +++ b/services/JiShe.CollectBus.Application/JiShe.CollectBus.Application.csproj @@ -23,13 +23,14 @@ - + + diff --git a/services/JiShe.CollectBus.Application/Samples/SampleAppService.cs b/services/JiShe.CollectBus.Application/Samples/SampleAppService.cs index 31a3494..ea2415e 100644 --- a/services/JiShe.CollectBus.Application/Samples/SampleAppService.cs +++ b/services/JiShe.CollectBus.Application/Samples/SampleAppService.cs @@ -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); } diff --git a/services/JiShe.CollectBus.Application/ScheduledMeterReading/BasicScheduledMeterReadingService.cs b/services/JiShe.CollectBus.Application/ScheduledMeterReading/BasicScheduledMeterReadingService.cs index a536e0a..208e1f1 100644 --- a/services/JiShe.CollectBus.Application/ScheduledMeterReading/BasicScheduledMeterReadingService.cs +++ b/services/JiShe.CollectBus.Application/ScheduledMeterReading/BasicScheduledMeterReadingService.cs @@ -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 meterInfos = new List(); - // List focusAddressDataLista = new List(); - // var timer1 = Stopwatch.StartNew(); + List meterInfos = new List(); + List focusAddressDataLista = new List(); + var timer1 = Stopwatch.StartNew(); - // var allIds = new HashSet(); - // decimal? score = null; - // string member = null; + var allIds = new HashSet(); + decimal? score = null; + string member = null; - // while (true) - // { - // var page = await _redisDataCacheService.GetAllPagedData( - // redisCacheMeterInfoHashKeyTemp, - // redisCacheMeterInfoZSetScoresIndexKeyTemp, - // pageSize: 1000, - // lastScore: score, - // lastMember: member); + while (true) + { + var page = await _redisDataCacheService.GetAllPagedData( + 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 /// 水表数据采集 /// /// - 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}分钟采集水表数据处理完成"); } /// @@ -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 /// 端到端采集项编码 /// 待采集时间,定时采集频率才是特殊情况,其他默认当前时间戳 /// 数据创建时间戳 + /// 数据包类型 /// - 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, diff --git a/services/JiShe.CollectBus.Application/ScheduledMeterReading/EnergySystemScheduledMeterReadingService.cs b/services/JiShe.CollectBus.Application/ScheduledMeterReading/EnergySystemScheduledMeterReadingService.cs index b0b6bba..883537c 100644 --- a/services/JiShe.CollectBus.Application/ScheduledMeterReading/EnergySystemScheduledMeterReadingService.cs +++ b/services/JiShe.CollectBus.Application/ScheduledMeterReading/EnergySystemScheduledMeterReadingService.cs @@ -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 _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; diff --git a/services/JiShe.CollectBus.Domain/Ammeters/ElectricityMeter.cs b/services/JiShe.CollectBus.Domain/Ammeters/ElectricityMeter.cs index ee132d3..9ba3c94 100644 --- a/services/JiShe.CollectBus.Domain/Ammeters/ElectricityMeter.cs +++ b/services/JiShe.CollectBus.Domain/Ammeters/ElectricityMeter.cs @@ -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] diff --git a/services/JiShe.CollectBus.Domain/Ammeters/ElectricityMeterTreeModel.cs b/services/JiShe.CollectBus.Domain/Ammeters/ElectricityMeterTreeModel.cs index 7fe7ebc..1f11198 100644 --- a/services/JiShe.CollectBus.Domain/Ammeters/ElectricityMeterTreeModel.cs +++ b/services/JiShe.CollectBus.Domain/Ammeters/ElectricityMeterTreeModel.cs @@ -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] diff --git a/services/JiShe.CollectBus.Domain/IotSystems/MeterReadingRecords/MeterReadingTelemetryPacketInfo.cs b/services/JiShe.CollectBus.Domain/IotSystems/MeterReadingRecords/MeterReadingTelemetryPacketInfo.cs index d26aed7..4b61e99 100644 --- a/services/JiShe.CollectBus.Domain/IotSystems/MeterReadingRecords/MeterReadingTelemetryPacketInfo.cs +++ b/services/JiShe.CollectBus.Domain/IotSystems/MeterReadingRecords/MeterReadingTelemetryPacketInfo.cs @@ -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 /// 抄读任务数据 /// [EntityType(EntityTypeEnum.TableModel)] + [SourceAnalyzers] public class MeterReadingTelemetryPacketInfo : IoTEntity { /// @@ -25,7 +18,13 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords /// [FIELDColumn] public string ScoreValue { get; set; } - + + /// + /// 数据包类型 + /// + [FIELDColumn] + public int PacketType { get; set; } + /// /// 是否手动操作 /// @@ -62,12 +61,6 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords /// [FIELDColumn] public string FocusAddress { get; set; } - - /// - /// 表Id - /// - [FIELDColumn] - public int MeterId { get; set; } /// /// 表地址 @@ -96,6 +89,7 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords /// /// 抄读计量点 /// + [FIELDColumn] public int Pn { get; set; } /// @@ -114,6 +108,7 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords /// /// 帧序列域 SEQ /// + [FIELDColumn] public int Seq { get; set; } /// @@ -132,7 +127,7 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords /// 发送次数 /// [FIELDColumn] - public int SendNum { get; set; }=0; + public int? SendNum { get; set; } /// /// 下次发送时间 diff --git a/services/JiShe.CollectBus.Domain/JiShe.CollectBus.Domain.csproj b/services/JiShe.CollectBus.Domain/JiShe.CollectBus.Domain.csproj index a60ffe1..f8880ec 100644 --- a/services/JiShe.CollectBus.Domain/JiShe.CollectBus.Domain.csproj +++ b/services/JiShe.CollectBus.Domain/JiShe.CollectBus.Domain.csproj @@ -1,8 +1,8 @@  - - - - + + + + net8.0 enable JiShe.CollectBus @@ -23,9 +23,12 @@ + - + + diff --git a/shared/JiShe.CollectBus.Analyzers.Shared/ISourceAnalyzersProvider.cs b/shared/JiShe.CollectBus.Analyzers.Shared/ISourceAnalyzersProvider.cs new file mode 100644 index 0000000..905f0ef --- /dev/null +++ b/shared/JiShe.CollectBus.Analyzers.Shared/ISourceAnalyzersProvider.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JiShe.CollectBus.Analyzers +{ + public interface ISourceAnalyzersProvider + { + /// + /// 获取属性值 + /// + /// + /// + /// + object GetPropertyValue(T entity, string propertyName); + + /// + /// 设置属性值 + /// + /// + /// + /// + void SetPropertyValue(T entity, string propertyName, object value); + + /// + /// 判断是否是元组属性 + /// + /// + /// + bool IsTupleProperty(string propertyName); + + /// + /// 获取元组属性值 + /// + /// + /// + /// + (object Item1, object Item2) GetTupleParts(T entity, string tuplePropertyName); + } +} diff --git a/shared/JiShe.CollectBus.Analyzers.Shared/JiShe.CollectBus.Analyzers.Shared.csproj b/shared/JiShe.CollectBus.Analyzers.Shared/JiShe.CollectBus.Analyzers.Shared.csproj new file mode 100644 index 0000000..3ae7562 --- /dev/null +++ b/shared/JiShe.CollectBus.Analyzers.Shared/JiShe.CollectBus.Analyzers.Shared.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.0 + + + diff --git a/shared/JiShe.CollectBus.Analyzers.Shared/SourceAnalyzersAttribute.cs b/shared/JiShe.CollectBus.Analyzers.Shared/SourceAnalyzersAttribute.cs new file mode 100644 index 0000000..0b33a6a --- /dev/null +++ b/shared/JiShe.CollectBus.Analyzers.Shared/SourceAnalyzersAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace JiShe.CollectBus.Analyzers.Shared +{ + /// + /// 标记需要生成源码的类 + /// + [AttributeUsage(AttributeTargets.Class)] + public class SourceAnalyzersAttribute : Attribute + { + } +} diff --git a/shared/JiShe.CollectBus.Common/Enums/TelemetryPacketTypeEnum.cs b/shared/JiShe.CollectBus.Common/Enums/TelemetryPacketTypeEnum.cs new file mode 100644 index 0000000..837392b --- /dev/null +++ b/shared/JiShe.CollectBus.Common/Enums/TelemetryPacketTypeEnum.cs @@ -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 +{ + /// + /// 遥测数据包类型枚举 + /// + public enum TelemetryPacketTypeEnum + { + /// + /// 1分钟密度 + /// + [Description("1分钟密度")] + AmmeterOneMinute = 1, + + /// + /// 5分钟密度 + /// + [Description("5分钟密度")] + AmmeterMeterFiveMinute = 5, + + /// + /// 15分钟密度 + /// + [Description("15分钟密度")] + AmmeterFifteenMinute = 15, + + /// + /// 自动校时 + /// + [Description("自动校时")] + AmmeterAutomaticVerificationTime = 16, + + /// + /// 日冻结 + /// + [Description("日冻结")] + AmmeterDayFreeze = 17, + + /// + /// 月冻结 + /// + [Description("月冻结")] + AmmeterMonthFreeze = 18, + + /// + /// 自动阀控 + /// + [Description("自动阀控")] + AmmeterAutoValveControl = 19, + + /// + /// 集中器终端版本 + /// + [Description("集中器终端版本")] + TerminalVersion = 20, + + /// + /// 集中器通信模块SIM + /// + [Description("集中器通信模块SIM")] + TelematicsModule = 21, + + /// + /// 水表抄读 + /// + [Description("水表抄读")] + WatermeterAutoReadding = 22, + } +} diff --git a/shared/JiShe.CollectBus.Common/JiShe.CollectBus.Common.csproj b/shared/JiShe.CollectBus.Common/JiShe.CollectBus.Common.csproj index 05645ef..6cf0246 100644 --- a/shared/JiShe.CollectBus.Common/JiShe.CollectBus.Common.csproj +++ b/shared/JiShe.CollectBus.Common/JiShe.CollectBus.Common.csproj @@ -17,7 +17,7 @@ - + @@ -25,8 +25,7 @@ - - + diff --git a/shared/JiShe.CollectBus.Common/Models/ServerApplicationOptions.cs b/shared/JiShe.CollectBus.Common/Models/ServerApplicationOptions.cs index 2eb92c5..525b5a2 100644 --- a/shared/JiShe.CollectBus.Common/Models/ServerApplicationOptions.cs +++ b/shared/JiShe.CollectBus.Common/Models/ServerApplicationOptions.cs @@ -8,12 +8,12 @@ /// /// 服务器标识 /// - public required string ServerTagName { get; set; } + public string ServerTagName { get; set; } /// /// 系统类型 /// - public required string SystemType { get; set; } + public string SystemType { get; set; } /// /// 首次采集时间 @@ -23,31 +23,31 @@ /// /// 自动验证时间 /// - public required string AutomaticVerificationTime { get; set; } + public string AutomaticVerificationTime { get; set; } /// /// 自动获取终端版时间 /// - public required string AutomaticTerminalVersionTime { get; set; } + public string AutomaticTerminalVersionTime { get; set; } /// /// 自动获取远程通信模块(SIM)版本时间 /// - public required string AutomaticTelematicsModuleTime { get; set; } + public string AutomaticTelematicsModuleTime { get; set; } /// /// 日冻结抄读时间 /// - public required string AutomaticDayFreezeTime { get; set; } + public string AutomaticDayFreezeTime { get; set; } /// /// 月冻结抄读时间 /// - public required string AutomaticMonthFreezeTime { get; set; } + public string AutomaticMonthFreezeTime { get; set; } /// /// 默认协议插件 /// - public required string DefaultProtocolPlugin { get; set; } + public string DefaultProtocolPlugin { get; set; } } } diff --git a/shared/JiShe.CollectBus.Domain.Shared/JiShe.CollectBus.Domain.Shared.csproj b/shared/JiShe.CollectBus.Domain.Shared/JiShe.CollectBus.Domain.Shared.csproj index 874b688..5453712 100644 --- a/shared/JiShe.CollectBus.Domain.Shared/JiShe.CollectBus.Domain.Shared.csproj +++ b/shared/JiShe.CollectBus.Domain.Shared/JiShe.CollectBus.Domain.Shared.csproj @@ -1,38 +1,38 @@ - + - - net8.0 - enable - JiShe.CollectBus - true - + + net8.0 + enable + JiShe.CollectBus + true + - - - - + + + + - - - + + + - - - - - - - + + + + + + + - - - - + + + + - - - + + + diff --git a/web/JiShe.CollectBus.Host/JiShe.CollectBus.Host.csproj b/web/JiShe.CollectBus.Host/JiShe.CollectBus.Host.csproj index 4ebd67d..5501841 100644 --- a/web/JiShe.CollectBus.Host/JiShe.CollectBus.Host.csproj +++ b/web/JiShe.CollectBus.Host/JiShe.CollectBus.Host.csproj @@ -5,7 +5,7 @@ enable enable True - + @@ -55,9 +55,9 @@ - - - + + + diff --git a/web/JiShe.CollectBus.Host/appsettings.json b/web/JiShe.CollectBus.Host/appsettings.json index 6c5e431..03eab38 100644 --- a/web/JiShe.CollectBus.Host/appsettings.json +++ b/web/JiShe.CollectBus.Host/appsettings.json @@ -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",