解决冲突
This commit is contained in:
commit
3490fc22f1
@ -1,4 +1,5 @@
|
|||||||
using Confluent.Kafka;
|
using Confluent.Kafka;
|
||||||
|
using JiShe.CollectBus.Common;
|
||||||
using JiShe.CollectBus.Common.Consts;
|
using JiShe.CollectBus.Common.Consts;
|
||||||
using JiShe.CollectBus.Kafka.Internal;
|
using JiShe.CollectBus.Kafka.Internal;
|
||||||
using JiShe.CollectBus.Kafka.Serialization;
|
using JiShe.CollectBus.Kafka.Serialization;
|
||||||
@ -30,6 +31,8 @@ namespace JiShe.CollectBus.Kafka.Consumer
|
|||||||
|
|
||||||
private readonly KafkaOptionConfig _kafkaOptionConfig;
|
private readonly KafkaOptionConfig _kafkaOptionConfig;
|
||||||
|
|
||||||
|
private readonly ServerApplicationOptions _applicationOptions;
|
||||||
|
|
||||||
private readonly KafkaPollyPipeline _kafkaPollyPipeline;
|
private readonly KafkaPollyPipeline _kafkaPollyPipeline;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -37,10 +40,11 @@ namespace JiShe.CollectBus.Kafka.Consumer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger"></param>
|
/// <param name="logger"></param>
|
||||||
/// <param name="kafkaOptionConfig"></param>
|
/// <param name="kafkaOptionConfig"></param>
|
||||||
public ConsumerService(ILogger<ConsumerService> logger, IOptions<KafkaOptionConfig> kafkaOptionConfig, KafkaPollyPipeline kafkaPollyPipeline)
|
public ConsumerService(ILogger<ConsumerService> logger, IOptions<KafkaOptionConfig> kafkaOptionConfig, KafkaPollyPipeline kafkaPollyPipeline, IOptions<ServerApplicationOptions> applicationOptions)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_kafkaOptionConfig = kafkaOptionConfig.Value;
|
_kafkaOptionConfig = kafkaOptionConfig.Value;
|
||||||
|
_applicationOptions = applicationOptions.Value;
|
||||||
_kafkaPollyPipeline = kafkaPollyPipeline;
|
_kafkaPollyPipeline = kafkaPollyPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +71,7 @@ namespace JiShe.CollectBus.Kafka.Consumer
|
|||||||
var config = new ConsumerConfig
|
var config = new ConsumerConfig
|
||||||
{
|
{
|
||||||
BootstrapServers = _kafkaOptionConfig.BootstrapServers,
|
BootstrapServers = _kafkaOptionConfig.BootstrapServers,
|
||||||
GroupId = groupId ?? _kafkaOptionConfig.ServerTagName,
|
GroupId = groupId ?? _applicationOptions.ServerTagName,
|
||||||
AutoOffsetReset = AutoOffsetReset.Earliest,
|
AutoOffsetReset = AutoOffsetReset.Earliest,
|
||||||
EnableAutoCommit = false, // 禁止AutoCommit
|
EnableAutoCommit = false, // 禁止AutoCommit
|
||||||
EnablePartitionEof = true, // 启用分区末尾标记
|
EnablePartitionEof = true, // 启用分区末尾标记
|
||||||
@ -161,7 +165,7 @@ namespace JiShe.CollectBus.Kafka.Consumer
|
|||||||
}
|
}
|
||||||
if (_kafkaOptionConfig.EnableFilter)
|
if (_kafkaOptionConfig.EnableFilter)
|
||||||
{
|
{
|
||||||
var headersFilter = new HeadersFilter { { "route-key", Encoding.UTF8.GetBytes(_kafkaOptionConfig.ServerTagName) } };
|
var headersFilter = new HeadersFilter { { "route-key", Encoding.UTF8.GetBytes(_applicationOptions.ServerTagName) } };
|
||||||
// 检查 Header 是否符合条件
|
// 检查 Header 是否符合条件
|
||||||
if (!headersFilter.Match(result.Message.Headers))
|
if (!headersFilter.Match(result.Message.Headers))
|
||||||
{
|
{
|
||||||
@ -244,7 +248,7 @@ namespace JiShe.CollectBus.Kafka.Consumer
|
|||||||
}
|
}
|
||||||
if (_kafkaOptionConfig.EnableFilter)
|
if (_kafkaOptionConfig.EnableFilter)
|
||||||
{
|
{
|
||||||
var headersFilter = new HeadersFilter { { "route-key", Encoding.UTF8.GetBytes(_kafkaOptionConfig.ServerTagName) } };
|
var headersFilter = new HeadersFilter { { "route-key", Encoding.UTF8.GetBytes(_applicationOptions.ServerTagName) } };
|
||||||
// 检查 Header 是否符合条件
|
// 检查 Header 是否符合条件
|
||||||
if (!headersFilter.Match(result.Message.Headers))
|
if (!headersFilter.Match(result.Message.Headers))
|
||||||
{
|
{
|
||||||
@ -348,7 +352,7 @@ namespace JiShe.CollectBus.Kafka.Consumer
|
|||||||
{
|
{
|
||||||
if (_kafkaOptionConfig.EnableFilter)
|
if (_kafkaOptionConfig.EnableFilter)
|
||||||
{
|
{
|
||||||
var headersFilter = new HeadersFilter { { "route-key", Encoding.UTF8.GetBytes(_kafkaOptionConfig.ServerTagName) } };
|
var headersFilter = new HeadersFilter { { "route-key", Encoding.UTF8.GetBytes(_applicationOptions.ServerTagName) } };
|
||||||
// 检查 Header 是否符合条件
|
// 检查 Header 是否符合条件
|
||||||
if (!headersFilter.Match(result.Message.Headers))
|
if (!headersFilter.Match(result.Message.Headers))
|
||||||
{
|
{
|
||||||
@ -485,7 +489,7 @@ namespace JiShe.CollectBus.Kafka.Consumer
|
|||||||
{
|
{
|
||||||
if (_kafkaOptionConfig.EnableFilter)
|
if (_kafkaOptionConfig.EnableFilter)
|
||||||
{
|
{
|
||||||
var headersFilter = new HeadersFilter { { "route-key", Encoding.UTF8.GetBytes(_kafkaOptionConfig.ServerTagName) } };
|
var headersFilter = new HeadersFilter { { "route-key", Encoding.UTF8.GetBytes(_applicationOptions.ServerTagName) } };
|
||||||
// 检查 Header 是否符合条件
|
// 检查 Header 是否符合条件
|
||||||
if (!headersFilter.Match(result.Message.Headers))
|
if (!headersFilter.Match(result.Message.Headers))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -9,11 +9,6 @@ public class KafkaOptionConfig
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string BootstrapServers { get; set; } = null!;
|
public string BootstrapServers { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 服务器标识
|
|
||||||
/// </summary>
|
|
||||||
public string ServerTagName { get; set; } = "KafkaFilterKey";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// kafka主题副本数量
|
/// kafka主题副本数量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -54,8 +49,4 @@ public class KafkaOptionConfig
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? SaslPassword { get; set; }
|
public string? SaslPassword { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 首次采集时间
|
|
||||||
/// </summary>
|
|
||||||
public DateTime? FirstCollectionTime { get; set; }
|
|
||||||
}
|
}
|
||||||
@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Confluent.Kafka;
|
using Confluent.Kafka;
|
||||||
|
using JiShe.CollectBus.Common;
|
||||||
using JiShe.CollectBus.Kafka.Consumer;
|
using JiShe.CollectBus.Kafka.Consumer;
|
||||||
using JiShe.CollectBus.Kafka.Internal;
|
using JiShe.CollectBus.Kafka.Internal;
|
||||||
using JiShe.CollectBus.Kafka.Serialization;
|
using JiShe.CollectBus.Kafka.Serialization;
|
||||||
@ -23,18 +24,19 @@ namespace JiShe.CollectBus.Kafka.Producer
|
|||||||
private readonly ConcurrentDictionary<Type, object> _producerCache = new();
|
private readonly ConcurrentDictionary<Type, object> _producerCache = new();
|
||||||
private class KafkaProducer<TKey, TValue> where TKey : notnull where TValue : class { }
|
private class KafkaProducer<TKey, TValue> where TKey : notnull where TValue : class { }
|
||||||
private readonly KafkaOptionConfig _kafkaOptionConfig;
|
private readonly KafkaOptionConfig _kafkaOptionConfig;
|
||||||
|
private readonly ServerApplicationOptions _applicationOptions;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ProducerService
|
/// ProducerService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="configuration"></param>
|
/// <param name="configuration"></param>
|
||||||
/// <param name="logger"></param>
|
/// <param name="logger"></param>
|
||||||
/// <param name="kafkaOptionConfig"></param>
|
/// <param name="kafkaOptionConfig"></param>
|
||||||
public ProducerService(IConfiguration configuration,ILogger<ProducerService> logger, IOptions<KafkaOptionConfig> kafkaOptionConfig)
|
public ProducerService(IConfiguration configuration,ILogger<ProducerService> logger, IOptions<KafkaOptionConfig> kafkaOptionConfig, IOptions<ServerApplicationOptions> applicationOptions)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_kafkaOptionConfig = kafkaOptionConfig.Value;
|
_kafkaOptionConfig = kafkaOptionConfig.Value;
|
||||||
|
_applicationOptions = applicationOptions.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region private 私有方法
|
#region private 私有方法
|
||||||
@ -119,7 +121,7 @@ namespace JiShe.CollectBus.Kafka.Producer
|
|||||||
Key = key,
|
Key = key,
|
||||||
Value = value,
|
Value = value,
|
||||||
Headers = new Headers{
|
Headers = new Headers{
|
||||||
{ "route-key", Encoding.UTF8.GetBytes(_kafkaOptionConfig.ServerTagName) }
|
{ "route-key", Encoding.UTF8.GetBytes(_applicationOptions.ServerTagName) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
await producer.ProduceAsync(topic, message);
|
await producer.ProduceAsync(topic, message);
|
||||||
@ -141,7 +143,7 @@ namespace JiShe.CollectBus.Kafka.Producer
|
|||||||
//Key= _kafkaOptionConfig.ServerTagName,
|
//Key= _kafkaOptionConfig.ServerTagName,
|
||||||
Value = value,
|
Value = value,
|
||||||
Headers = new Headers{
|
Headers = new Headers{
|
||||||
{ "route-key", Encoding.UTF8.GetBytes(_kafkaOptionConfig.ServerTagName) }
|
{ "route-key", Encoding.UTF8.GetBytes(_applicationOptions.ServerTagName) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
await producer.ProduceAsync(topic, message);
|
await producer.ProduceAsync(topic, message);
|
||||||
@ -165,7 +167,7 @@ namespace JiShe.CollectBus.Kafka.Producer
|
|||||||
Key = key,
|
Key = key,
|
||||||
Value = value,
|
Value = value,
|
||||||
Headers = new Headers{
|
Headers = new Headers{
|
||||||
{ "route-key", Encoding.UTF8.GetBytes(_kafkaOptionConfig.ServerTagName) }
|
{ "route-key", Encoding.UTF8.GetBytes(_applicationOptions.ServerTagName) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var typeKey = typeof(KafkaProducer<TKey, TValue>);
|
var typeKey = typeof(KafkaProducer<TKey, TValue>);
|
||||||
@ -200,7 +202,7 @@ namespace JiShe.CollectBus.Kafka.Producer
|
|||||||
//Key = _kafkaOptionConfig.ServerTagName,
|
//Key = _kafkaOptionConfig.ServerTagName,
|
||||||
Value = value,
|
Value = value,
|
||||||
Headers = new Headers{
|
Headers = new Headers{
|
||||||
{ "route-key", Encoding.UTF8.GetBytes(_kafkaOptionConfig.ServerTagName) }
|
{ "route-key", Encoding.UTF8.GetBytes(_applicationOptions.ServerTagName) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var typeKey = typeof(KafkaProducer<Null, TValue>);
|
var typeKey = typeof(KafkaProducer<Null, TValue>);
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
using System;
|
using JiShe.CollectBus.Common.BuildSendDatas;
|
||||||
|
using JiShe.CollectBus.Common.Enums;
|
||||||
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using JiShe.CollectBus.Common.Consts;
|
||||||
using JiShe.CollectBus.Common.Extensions;
|
using JiShe.CollectBus.Common.Extensions;
|
||||||
|
using JiShe.CollectBus.Common.Models;
|
||||||
|
using JiShe.CollectBus.FreeRedis;
|
||||||
using JiShe.CollectBus.IotSystems.Protocols;
|
using JiShe.CollectBus.IotSystems.Protocols;
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Models;
|
using JiShe.CollectBus.Protocol.Contracts.Models;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.SendData;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using TouchSocket.Sockets;
|
using TouchSocket.Sockets;
|
||||||
@ -11,7 +17,7 @@ using Volo.Abp.Domain.Repositories;
|
|||||||
|
|
||||||
namespace JiShe.CollectBus.Protocol.Contracts.Abstracts
|
namespace JiShe.CollectBus.Protocol.Contracts.Abstracts
|
||||||
{
|
{
|
||||||
public abstract class ProtocolPlugin:IProtocolPlugin
|
public abstract class ProtocolPlugin : IProtocolPlugin
|
||||||
{
|
{
|
||||||
//头部字节长度
|
//头部字节长度
|
||||||
public const int hearderLen = 6;
|
public const int hearderLen = 6;
|
||||||
@ -22,10 +28,13 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts
|
|||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IRepository<ProtocolInfo, Guid> _protocolInfoRepository;
|
private readonly IRepository<ProtocolInfo, Guid> _protocolInfoRepository;
|
||||||
|
private readonly IFreeRedisProvider _redisProvider;
|
||||||
|
|
||||||
public ProtocolPlugin(IServiceProvider serviceProvider, ILogger logger)
|
public ProtocolPlugin(IServiceProvider serviceProvider, ILogger logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_protocolInfoRepository = serviceProvider.GetRequiredService<IRepository<ProtocolInfo, Guid>>();
|
_protocolInfoRepository = serviceProvider.GetRequiredService<IRepository<ProtocolInfo, Guid>>();
|
||||||
|
_redisProvider = serviceProvider.GetRequiredService<IFreeRedisProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -42,10 +51,11 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts
|
|||||||
|
|
||||||
await _protocolInfoRepository.DeleteDirectAsync(a => a.Name == Info.Name);
|
await _protocolInfoRepository.DeleteDirectAsync(a => a.Name == Info.Name);
|
||||||
await _protocolInfoRepository.InsertAsync(Info);
|
await _protocolInfoRepository.InsertAsync(Info);
|
||||||
//await _protocolInfoCache.Get()
|
await _redisProvider.Instance.HDelAsync($"{RedisConst.ProtocolKey}", Info.Name);
|
||||||
|
await _redisProvider.Instance.HSetAsync($"{RedisConst.ProtocolKey}", Info.Name, Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Task<T> AnalyzeAsync<T>(ITcpSessionClient client, string messageReceived, Action<T>? receivedAction = null) where T :class;
|
public abstract Task<T> AnalyzeAsync<T>(ITcpSessionClient client, string messageReceived, Action<T>? receivedAction = null) where T : class;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -80,7 +90,7 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts
|
|||||||
DA = Analysis_DA(hexStringList),
|
DA = Analysis_DA(hexStringList),
|
||||||
DT = Analysis_DT(hexStringList)
|
DT = Analysis_DT(hexStringList)
|
||||||
};
|
};
|
||||||
return tB3761;
|
return tB3761;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -378,5 +388,18 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static int CalculateFn(string dt1, string dt2) => dt2.HexToDec() * 8 + (8 - dt1.HexTo4BinZero().IndexOf("1"));
|
public static int CalculateFn(string dt1, string dt2) => dt2.HexToDec() * 8 + (8 - dt1.HexTo4BinZero().IndexOf("1"));
|
||||||
|
|
||||||
|
#region 下行命令构建
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 组装报文
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="entity">设备数据实体</param>
|
||||||
|
/// <param name="afnFnCode">映射读取执行方法的Code,例如10_1,表示 10H_F1_00000,10H_F1_00001,统一英文下划线分隔</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract Task<ProtocolBuildResponse> BuildAsync(ProtocolBuildRequest request);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using JiShe.CollectBus.Common.Models;
|
|||||||
using JiShe.CollectBus.IotSystems.MessageReceiveds;
|
using JiShe.CollectBus.IotSystems.MessageReceiveds;
|
||||||
using JiShe.CollectBus.IotSystems.Protocols;
|
using JiShe.CollectBus.IotSystems.Protocols;
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Models;
|
using JiShe.CollectBus.Protocol.Contracts.Models;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.SendData;
|
||||||
using TouchSocket.Sockets;
|
using TouchSocket.Sockets;
|
||||||
|
|
||||||
namespace JiShe.CollectBus.Protocol.Contracts.Interfaces
|
namespace JiShe.CollectBus.Protocol.Contracts.Interfaces
|
||||||
@ -18,6 +19,14 @@ namespace JiShe.CollectBus.Protocol.Contracts.Interfaces
|
|||||||
|
|
||||||
TB3761? Analysis3761(string messageReceived);
|
TB3761? Analysis3761(string messageReceived);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 组装报文
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">是否需要转发的扩展协议入参对象</typeparam>
|
||||||
|
/// <param name="afnFnCode">映射读取执行方法的Code,例如10_1,表示10H_F1</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<ProtocolBuildResponse> BuildAsync(ProtocolBuildRequest request);
|
||||||
|
|
||||||
//Task LoginAsync(MessageReceivedLogin messageReceived);
|
//Task LoginAsync(MessageReceivedLogin messageReceived);
|
||||||
|
|
||||||
//Task HeartbeatAsync(MessageReceivedHeartbeat messageReceived);
|
//Task HeartbeatAsync(MessageReceivedHeartbeat messageReceived);
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
using JiShe.CollectBus.Protocol.Contracts.Models;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Protocol.Contracts.SendData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 报文构建参数
|
||||||
|
/// </summary>
|
||||||
|
public class ProtocolBuildRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 集中器地址
|
||||||
|
/// </summary>
|
||||||
|
public required string FocusAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 抄读计量点,也就是终端电表对应端口
|
||||||
|
/// </summary>
|
||||||
|
public int Pn { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 3761协议构建组合功能码
|
||||||
|
/// </summary>
|
||||||
|
public required string ItemCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 集中器转发协议构建构建参数
|
||||||
|
/// </summary>
|
||||||
|
public SubProtocolBuildRequest SubProtocolRequest { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
namespace JiShe.CollectBus.Protocol.Contracts.SendData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 报文构建返回结果
|
||||||
|
/// </summary>
|
||||||
|
public class ProtocolBuildResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 是否成功
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSuccess { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 帧功能域AFN
|
||||||
|
/// </summary>
|
||||||
|
public int AFn { get; set;}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 帧功能域FN
|
||||||
|
/// </summary>
|
||||||
|
public int Fn { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 帧序列域SEQ
|
||||||
|
/// </summary>
|
||||||
|
public int Seq { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 地址域A3的主站地址MSA
|
||||||
|
/// </summary>
|
||||||
|
public int MSA { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报文体
|
||||||
|
/// </summary>
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Protocol.Contracts.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 子协议构建参数
|
||||||
|
/// </summary>
|
||||||
|
public class SubProtocolBuildRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 表地址
|
||||||
|
/// </summary>
|
||||||
|
public required string MeterAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 密码
|
||||||
|
/// </summary>
|
||||||
|
public required string Password { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 操作码
|
||||||
|
/// </summary>
|
||||||
|
public required string ItemCode { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,51 +1,42 @@
|
|||||||
using JiShe.CollectBus.Common.Enums;
|
using JiShe.CollectBus.Common.BuildSendDatas;
|
||||||
|
using JiShe.CollectBus.Common.Enums;
|
||||||
using JiShe.CollectBus.Common.Models;
|
using JiShe.CollectBus.Common.Models;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data.SqlTypes;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace JiShe.CollectBus.Common.BuildSendDatas
|
namespace JiShe.CollectBus.Protocol.Contracts.SendData
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建下发报文,只适用与定时抄读
|
/// 构建3761下发报文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class TelemetryPacketBuilder
|
public static class Telemetry3761PacketBuilder
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建报文的委托
|
/// 构建报文的委托
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="request.FocusAddress"></param>
|
public delegate Telemetry3761PacketResponse T3761Delegate(Telemetry3761PacketRequest request);
|
||||||
/// <param name="request.Fn"></param>
|
|
||||||
/// <param name="request.Pn"></param>
|
|
||||||
public delegate TelemetryPacketResponse AFNDelegate(TelemetryPacketRequest request);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 编码与方法的映射表
|
/// 编码与方法的映射表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly Dictionary<string, AFNDelegate> AFNHandlersDictionary = new();
|
public static readonly Dictionary<string, T3761Delegate> T3761AFNHandlers = new();
|
||||||
|
|
||||||
static TelemetryPacketBuilder()
|
static Telemetry3761PacketBuilder()
|
||||||
{
|
{
|
||||||
// 初始化时自动注册所有符合命名规则的方法
|
// 初始化时自动注册所有符合命名规则的方法
|
||||||
var methods = typeof(TelemetryPacketBuilder).GetMethods(BindingFlags.Static | BindingFlags.Public);
|
var methods = typeof(Telemetry3761PacketBuilder).GetMethods(BindingFlags.Static | BindingFlags.Public);
|
||||||
foreach (var method in methods)
|
foreach (var method in methods)
|
||||||
{
|
{
|
||||||
if (method.Name.StartsWith("AFN") && method.Name.EndsWith("_Fn_Send"))
|
if (method.Name.StartsWith("AFN") && method.Name.EndsWith("_Fn_Send"))
|
||||||
{
|
{
|
||||||
string code = method.Name;
|
string code = method.Name;
|
||||||
var delegateInstance = (AFNDelegate)Delegate.CreateDelegate(typeof(AFNDelegate), method);
|
var delegateInstance = (T3761Delegate)Delegate.CreateDelegate(typeof(T3761Delegate), method);
|
||||||
AFNHandlersDictionary[code] = delegateInstance;
|
T3761AFNHandlers[code] = delegateInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region AFN_00H 确认∕否认
|
#region AFN_00H 确认∕否认
|
||||||
public static TelemetryPacketResponse AFN00_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN00_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -64,13 +55,13 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region AFN_01H 复位命令
|
#region AFN_01H 复位命令
|
||||||
public static TelemetryPacketResponse AFN01_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN01_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -89,13 +80,13 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region AFN_02H 链路接口检测
|
#region AFN_02H 链路接口检测
|
||||||
public static TelemetryPacketResponse AFN02_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN02_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -114,12 +105,12 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AFN_04H 设置参数
|
#region AFN_04H 设置参数
|
||||||
public static TelemetryPacketResponse AFN04_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN04_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -138,13 +129,13 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AFN_05H 控制命令
|
#region AFN_05H 控制命令
|
||||||
public static TelemetryPacketResponse AFN05_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN05_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -163,12 +154,12 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AFN_09H 请求终端配置及信息
|
#region AFN_09H 请求终端配置及信息
|
||||||
public static TelemetryPacketResponse AFN09_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN09_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -187,13 +178,13 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AFN_0AH 查询参数
|
#region AFN_0AH 查询参数
|
||||||
public static TelemetryPacketResponse AFN0A_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN0A_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -212,12 +203,12 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AFN_0CH 请求一类数据
|
#region AFN_0CH 请求一类数据
|
||||||
public static TelemetryPacketResponse AFN0C_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN0C_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -236,12 +227,12 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AFN_0DH 请求二类数据
|
#region AFN_0DH 请求二类数据
|
||||||
public static TelemetryPacketResponse AFN0D_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN0D_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -260,12 +251,12 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region AFN10H 数据转发
|
#region AFN10H 数据转发
|
||||||
public static TelemetryPacketResponse AFN10_Fn_Send(TelemetryPacketRequest request)
|
public static Telemetry3761PacketResponse AFN10_Fn_Send(Telemetry3761PacketRequest request)
|
||||||
{
|
{
|
||||||
var reqParameter = new ReqParameter2()
|
var reqParameter = new ReqParameter2()
|
||||||
{
|
{
|
||||||
@ -284,7 +275,7 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
Fn = request.Fn
|
Fn = request.Fn
|
||||||
};
|
};
|
||||||
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter, request.DataUnit);
|
var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter, request.DataUnit);
|
||||||
return new TelemetryPacketResponse() { Seq = reqParameter.Seq, Data = bytes, MSA = reqParameter.MSA, };
|
return new Telemetry3761PacketResponse() { Seq = reqParameter.Seq.PRSEQ, Data = bytes, MSA = reqParameter.MSA, };
|
||||||
}
|
}
|
||||||
|
|
||||||
#region SpecialAmmeter 特殊电表转发
|
#region SpecialAmmeter 特殊电表转发
|
||||||
@ -1,20 +1,14 @@
|
|||||||
using System;
|
namespace JiShe.CollectBus.Protocol.Contracts.SendData
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace JiShe.CollectBus.Common.BuildSendDatas
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 报文构建参数
|
/// 构建3761报文参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TelemetryPacketRequest
|
public class Telemetry3761PacketRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 集中器地址
|
/// 集中器地址
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string FocusAddress { get; set; }
|
public required string FocusAddress { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 抄读功能码
|
/// 抄读功能码
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
namespace JiShe.CollectBus.Protocol.Contracts.SendData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 返回3761报文结果
|
||||||
|
/// </summary>
|
||||||
|
public class Telemetry3761PacketResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 帧序列域SEQ
|
||||||
|
/// </summary>
|
||||||
|
public int Seq { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 地址域A3的主站地址MSA
|
||||||
|
/// </summary>
|
||||||
|
public int MSA { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报文体
|
||||||
|
/// </summary>
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
using Volo.Abp;
|
using Volo.Abp;
|
||||||
using Volo.Abp.Modularity;
|
using Volo.Abp.Modularity;
|
||||||
|
|
||||||
@ -15,9 +16,30 @@ namespace JiShe.CollectBus.Protocol.Test
|
|||||||
|
|
||||||
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||||
{
|
{
|
||||||
Console.WriteLine("TestProtocolPlugin Initialization");
|
Console.WriteLine("TestProtocolPlugin OnApplicationInitializationAsync");
|
||||||
var protocol = context.ServiceProvider.GetRequiredKeyedService<IProtocolPlugin>(nameof(TestProtocolPlugin));
|
var protocol = context.ServiceProvider.GetRequiredKeyedService<IProtocolPlugin>(nameof(TestProtocolPlugin));
|
||||||
|
RemoveServiceAtRuntime(context.ServiceProvider);
|
||||||
await protocol.LoadAsync();
|
await protocol.LoadAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnApplicationShutdown(ApplicationShutdownContext context)
|
||||||
|
{
|
||||||
|
Console.WriteLine("TestProtocolPlugin OnApplicationShutdown");
|
||||||
|
base.OnApplicationShutdown(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveServiceAtRuntime(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var services = serviceProvider.GetService<IServiceCollection>();
|
||||||
|
services?.AddKeyedSingleton<IProtocolPlugin, TestProtocolPlugin>(nameof(TestProtocolPlugin));
|
||||||
|
|
||||||
|
|
||||||
|
//var services = (IServiceCollection)serviceProvider.GetService(typeof(IServiceCollection));
|
||||||
|
//var pluginService = serviceProvider.GetKeyedService<IProtocolPlugin>(nameof(TestProtocolPlugin));
|
||||||
|
//if (services != null && pluginService!=null)
|
||||||
|
//{
|
||||||
|
// services.Remove(pluginService);
|
||||||
|
//}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using JiShe.CollectBus.Common.Models;
|
|||||||
using JiShe.CollectBus.IotSystems.MessageReceiveds;
|
using JiShe.CollectBus.IotSystems.MessageReceiveds;
|
||||||
using JiShe.CollectBus.IotSystems.Protocols;
|
using JiShe.CollectBus.IotSystems.Protocols;
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Abstracts;
|
using JiShe.CollectBus.Protocol.Contracts.Abstracts;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.SendData;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using TouchSocket.Sockets;
|
using TouchSocket.Sockets;
|
||||||
|
|
||||||
@ -20,11 +21,16 @@ namespace JiShe.CollectBus.Protocol.Test
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed override ProtocolInfo Info => new(nameof(TestProtocolPlugin), "Test", "TCP", "Test协议", "DTS1980-Test");
|
public sealed override ProtocolInfo Info => new(nameof(TestProtocolPlugin), "Test", "TCP", "Test协议", "DTS1980-TEST");
|
||||||
|
|
||||||
public override Task<T> AnalyzeAsync<T>(ITcpSessionClient client, string messageReceived, Action<T>? receivedAction = null)
|
public override Task<T> AnalyzeAsync<T>(ITcpSessionClient client, string messageReceived, Action<T>? receivedAction = null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Task<ProtocolBuildResponse> BuildAsync(ProtocolBuildRequest request)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,6 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Serilog.Core;
|
using Serilog.Core;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using TouchSocket.Core;
|
|
||||||
using Volo.Abp;
|
using Volo.Abp;
|
||||||
using Volo.Abp.Modularity;
|
using Volo.Abp.Modularity;
|
||||||
|
|
||||||
@ -21,7 +20,6 @@ namespace JiShe.CollectBus.Protocol
|
|||||||
{
|
{
|
||||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||||
{
|
{
|
||||||
Console.WriteLine("StandardProtocolPlugin ConfigureServices");
|
|
||||||
context.Services.AddKeyedSingleton<IProtocolPlugin, StandardProtocolPlugin>(nameof(StandardProtocolPlugin));
|
context.Services.AddKeyedSingleton<IProtocolPlugin, StandardProtocolPlugin>(nameof(StandardProtocolPlugin));
|
||||||
//RegisterProtocolAnalysis(context.Services);
|
//RegisterProtocolAnalysis(context.Services);
|
||||||
LoadAnalysisStrategy(context.Services);
|
LoadAnalysisStrategy(context.Services);
|
||||||
@ -29,11 +27,17 @@ namespace JiShe.CollectBus.Protocol
|
|||||||
|
|
||||||
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||||
{
|
{
|
||||||
Console.WriteLine("StandardProtocolPlugin Initialization");
|
Console.WriteLine("StandardProtocolPlugin OnApplicationInitializationAsync");
|
||||||
var standardProtocol = context.ServiceProvider.GetRequiredKeyedService<IProtocolPlugin>(nameof(StandardProtocolPlugin));
|
var standardProtocol = context.ServiceProvider.GetRequiredKeyedService<IProtocolPlugin>(nameof(StandardProtocolPlugin));
|
||||||
await standardProtocol.LoadAsync();
|
await standardProtocol.LoadAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnApplicationShutdown(ApplicationShutdownContext context)
|
||||||
|
{
|
||||||
|
Console.WriteLine("StandardProtocolPlugin OnApplicationShutdown");
|
||||||
|
base.OnApplicationShutdown(context);
|
||||||
|
}
|
||||||
|
|
||||||
public void LoadAnalysisStrategy(IServiceCollection services)
|
public void LoadAnalysisStrategy(IServiceCollection services)
|
||||||
{
|
{
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
|||||||
@ -0,0 +1,106 @@
|
|||||||
|
using FreeSql;
|
||||||
|
using JiShe.CollectBus.Common.BuildSendDatas;
|
||||||
|
using JiShe.CollectBus.Common.Enums;
|
||||||
|
using JiShe.CollectBus.Common.Extensions;
|
||||||
|
using JiShe.CollectBus.Common.Models;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Protocol.SendData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构建645-2007下发报文
|
||||||
|
/// </summary>
|
||||||
|
public static class Telemetry645PacketBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构建报文的委托
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public delegate Telemetry645PacketResponse T645Delegate(Telemetry645PacketRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 编码与方法的映射表
|
||||||
|
/// </summary>
|
||||||
|
public static readonly Dictionary<string, T645Delegate> T645ControlHandlers = new();
|
||||||
|
|
||||||
|
static Telemetry645PacketBuilder()
|
||||||
|
{
|
||||||
|
// 初始化时自动注册所有符合命名规则的方法
|
||||||
|
var methods = typeof(Telemetry645PacketBuilder).GetMethods(BindingFlags.Static | BindingFlags.Public);
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
if (method.Name.StartsWith("C") && method.Name.EndsWith("_Send"))
|
||||||
|
{
|
||||||
|
string code = method.Name;
|
||||||
|
var delegateInstance = (T645Delegate)Delegate.CreateDelegate(typeof(T645Delegate), method);
|
||||||
|
T645ControlHandlers[code] = delegateInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 1CH 跳合闸、报警、保电
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1CH 跳合闸
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Telemetry645PacketResponse C1C_01_Send(Telemetry645PacketRequest request)
|
||||||
|
{
|
||||||
|
var itemCodeArr = request.ItemCode.Split('_');
|
||||||
|
var c_data = itemCodeArr[0];
|
||||||
|
var n_data = itemCodeArr[1];
|
||||||
|
string password = request.Password;
|
||||||
|
string pwdLevel = "02";
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(password) && password.Contains("|"))
|
||||||
|
{
|
||||||
|
var sp = password.Split('|');
|
||||||
|
password = sp[0];
|
||||||
|
pwdLevel = sp[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var strDate = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan();//命令有效截止时间
|
||||||
|
|
||||||
|
var strP = password.StrAddSpan().StrReverseOrder();
|
||||||
|
var strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + n_data + " 00 " + strDate;
|
||||||
|
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
|
||||||
|
|
||||||
|
var dataList = Build645SendData.Build645SendCommand(request.MeterAddress, c_data, dataUnit);
|
||||||
|
return new Telemetry645PacketResponse() { Data = dataList };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1CH 保电
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Telemetry645PacketResponse C1C_03_Send(Telemetry645PacketRequest request)
|
||||||
|
{
|
||||||
|
var itemCodeArr = request.ItemCode.Split('_');
|
||||||
|
var c_data = itemCodeArr[0];
|
||||||
|
var n_data = itemCodeArr[1];
|
||||||
|
string password = request.Password;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(password) && password.Contains("|"))
|
||||||
|
{
|
||||||
|
var sp = password.Split('|');
|
||||||
|
password = sp[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var strDate = (n_data + DateTime.Now.AddDays(1).ToString("00000012ddMMyy")).StrAddSpan();
|
||||||
|
|
||||||
|
var strP = password.StrAddSpan().StrReverseOrder();
|
||||||
|
|
||||||
|
var strSJY = " 02 " + strP + " 01 00 00 00 " + strDate;
|
||||||
|
|
||||||
|
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
|
||||||
|
|
||||||
|
var dataList = Build645SendData.Build645SendCommand(request.MeterAddress, c_data, dataUnit);
|
||||||
|
return new Telemetry645PacketResponse() { Data = dataList };
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
namespace JiShe.CollectBus.Protocol.SendData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构建645报文参数
|
||||||
|
/// </summary>
|
||||||
|
public class Telemetry645PacketRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 表地址
|
||||||
|
/// </summary>
|
||||||
|
public required string MeterAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 密码
|
||||||
|
/// </summary>
|
||||||
|
public required string Password { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 操作码
|
||||||
|
/// </summary>
|
||||||
|
public required string ItemCode { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
namespace JiShe.CollectBus.Protocol.SendData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 返回645报文结果
|
||||||
|
/// </summary>
|
||||||
|
public class Telemetry645PacketResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 报文体
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
using DeviceDetectorNET.Parser.Device;
|
using JiShe.CollectBus.Common.BuildSendDatas;
|
||||||
using JiShe.CollectBus.Common.BuildSendDatas;
|
|
||||||
using JiShe.CollectBus.Common.Consts;
|
using JiShe.CollectBus.Common.Consts;
|
||||||
using JiShe.CollectBus.Common.Enums;
|
using JiShe.CollectBus.Common.Enums;
|
||||||
using JiShe.CollectBus.Common.Extensions;
|
using JiShe.CollectBus.Common.Extensions;
|
||||||
@ -11,11 +10,12 @@ using JiShe.CollectBus.IotSystems.MessageReceiveds;
|
|||||||
using JiShe.CollectBus.IotSystems.Protocols;
|
using JiShe.CollectBus.IotSystems.Protocols;
|
||||||
using JiShe.CollectBus.Kafka.Producer;
|
using JiShe.CollectBus.Kafka.Producer;
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Abstracts;
|
using JiShe.CollectBus.Protocol.Contracts.Abstracts;
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Models;
|
using JiShe.CollectBus.Protocol.Contracts.Models;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.SendData;
|
||||||
|
using JiShe.CollectBus.Protocol.SendData;
|
||||||
|
using Mapster;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using TouchSocket.Sockets;
|
using TouchSocket.Sockets;
|
||||||
using Volo.Abp.Domain.Repositories;
|
using Volo.Abp.Domain.Repositories;
|
||||||
|
|
||||||
@ -30,17 +30,22 @@ namespace JiShe.CollectBus.Protocol
|
|||||||
private readonly IRepository<Device, Guid> _deviceRepository;
|
private readonly IRepository<Device, Guid> _deviceRepository;
|
||||||
private readonly ITcpService _tcpService;
|
private readonly ITcpService _tcpService;
|
||||||
|
|
||||||
|
public readonly Dictionary<string, Telemetry3761PacketBuilder.T3761Delegate> T3761AFNHandlers;
|
||||||
|
public readonly Dictionary<string, Telemetry645PacketBuilder.T645Delegate> T645ControlHandlers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="StandardProtocolPlugin"/> class.
|
/// Initializes a new instance of the <see cref="StandardProtocolPlugin"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serviceProvider">The service provider.</param>
|
/// <param name="serviceProvider">The service provider.</param>
|
||||||
public StandardProtocolPlugin(IServiceProvider serviceProvider,ILogger<StandardProtocolPlugin> logger, ITcpService tcpService) : base(serviceProvider, logger)
|
public StandardProtocolPlugin(IServiceProvider serviceProvider, ILogger<StandardProtocolPlugin> logger, ITcpService tcpService) : base(serviceProvider, logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
//_logger = serviceProvider.GetRequiredService<ILogger<StandardProtocolPlugin>>();
|
//_logger = serviceProvider.GetRequiredService<ILogger<StandardProtocolPlugin>>();
|
||||||
_producerService = serviceProvider.GetRequiredService<IProducerService>();
|
_producerService = serviceProvider.GetRequiredService<IProducerService>();
|
||||||
_deviceRepository = serviceProvider.GetRequiredService<IRepository<Device, Guid>>();
|
_deviceRepository = serviceProvider.GetRequiredService<IRepository<Device, Guid>>();
|
||||||
_tcpService = tcpService;
|
_tcpService = tcpService;
|
||||||
|
T3761AFNHandlers = Telemetry3761PacketBuilder.T3761AFNHandlers;
|
||||||
|
T645ControlHandlers = Telemetry645PacketBuilder.T645ControlHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed override ProtocolInfo Info => new(nameof(StandardProtocolPlugin), "376.1", "TCP", "376.1协议", "DTS1980");
|
public sealed override ProtocolInfo Info => new(nameof(StandardProtocolPlugin), "376.1", "TCP", "376.1协议", "DTS1980");
|
||||||
@ -144,7 +149,7 @@ namespace JiShe.CollectBus.Protocol
|
|||||||
/// <param name="msa"></param>
|
/// <param name="msa"></param>
|
||||||
/// <param name="pseq"></param>
|
/// <param name="pseq"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task LoginAsync(ITcpSessionClient client,string messageReceived, string code, int? msa, int? pseq)
|
public async Task LoginAsync(ITcpSessionClient client, string messageReceived, string code, int? msa, int? pseq)
|
||||||
{
|
{
|
||||||
string oldClientId = $"{client.Id}";
|
string oldClientId = $"{client.Id}";
|
||||||
await client.ResetIdAsync(code);
|
await client.ResetIdAsync(code);
|
||||||
@ -183,7 +188,7 @@ namespace JiShe.CollectBus.Protocol
|
|||||||
AFN = AFN.确认或否认,
|
AFN = AFN.确认或否认,
|
||||||
FunCode = (int)CFromStationFunCode.链路数据,
|
FunCode = (int)CFromStationFunCode.链路数据,
|
||||||
PRM = PRM.从动站报文,
|
PRM = PRM.从动站报文,
|
||||||
A =code,
|
A = code,
|
||||||
Seq = new Seq()
|
Seq = new Seq()
|
||||||
{
|
{
|
||||||
TpV = TpV.附加信息域中无时间标签,
|
TpV = TpV.附加信息域中无时间标签,
|
||||||
@ -200,7 +205,8 @@ namespace JiShe.CollectBus.Protocol
|
|||||||
{
|
{
|
||||||
ClientId = messageReceivedLoginEvent.ClientId,
|
ClientId = messageReceivedLoginEvent.ClientId,
|
||||||
DeviceNo = messageReceivedLoginEvent.DeviceNo,
|
DeviceNo = messageReceivedLoginEvent.DeviceNo,
|
||||||
Message = bytes, Type = IssuedEventType.Login,
|
Message = bytes,
|
||||||
|
Type = IssuedEventType.Login,
|
||||||
MessageId = messageReceivedLoginEvent.MessageId
|
MessageId = messageReceivedLoginEvent.MessageId
|
||||||
};
|
};
|
||||||
if (_tcpService.ClientExists(issuedEventMessage.ClientId))
|
if (_tcpService.ClientExists(issuedEventMessage.ClientId))
|
||||||
@ -219,7 +225,7 @@ namespace JiShe.CollectBus.Protocol
|
|||||||
/// <param name="msa"></param>
|
/// <param name="msa"></param>
|
||||||
/// <param name="pseq"></param>
|
/// <param name="pseq"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task HeartbeatAsync(ITcpSessionClient client,string messageReceived, string code, int? msa, int? pseq)
|
public async Task HeartbeatAsync(ITcpSessionClient client, string messageReceived, string code, int? msa, int? pseq)
|
||||||
{
|
{
|
||||||
|
|
||||||
string clientId = code;
|
string clientId = code;
|
||||||
@ -297,8 +303,78 @@ namespace JiShe.CollectBus.Protocol
|
|||||||
_logger.LogWarning($"集中器地址{issuedEventMessage.ClientId} 心跳回复下发内容:{Convert.ToHexString(bytes)}");
|
_logger.LogWarning($"集中器地址{issuedEventMessage.ClientId} 心跳回复下发内容:{Convert.ToHexString(bytes)}");
|
||||||
await _producerService.ProduceAsync(ProtocolConst.SubscriberHeartbeatIssuedEventName, issuedEventMessage);
|
await _producerService.ProduceAsync(ProtocolConst.SubscriberHeartbeatIssuedEventName, issuedEventMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 组装报文
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">报文构建参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override async Task<ProtocolBuildResponse> BuildAsync(ProtocolBuildRequest request)
|
||||||
|
{
|
||||||
|
if (request == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"{nameof(StandardProtocolPlugin)} 报文构建失败,参数为空");
|
||||||
|
}
|
||||||
|
var itemCodeArr = request.ItemCode.Split('_');
|
||||||
|
var aFNStr = itemCodeArr[0];
|
||||||
|
var aFN = (AFN)aFNStr.HexToDec();
|
||||||
|
var fn = int.Parse(itemCodeArr[1]);
|
||||||
|
Telemetry3761PacketResponse builderResponse = null;
|
||||||
|
|
||||||
|
List<string> dataUnit = new List<string>();
|
||||||
|
//数据转发场景 10H_F1_1CH
|
||||||
|
if (aFNStr == "10" && request.SubProtocolRequest != null && string.IsNullOrWhiteSpace(request.SubProtocolRequest.ItemCode) == false)
|
||||||
|
{
|
||||||
|
var t645PacketHandlerName = $"C{request.SubProtocolRequest.ItemCode}_Send";
|
||||||
|
Telemetry645PacketResponse t645PacketResponse = null;
|
||||||
|
|
||||||
|
if (T645ControlHandlers != null && T645ControlHandlers.TryGetValue(t645PacketHandlerName
|
||||||
|
, out var t645PacketHandler))
|
||||||
|
{
|
||||||
|
t645PacketResponse = t645PacketHandler(new Telemetry645PacketRequest()
|
||||||
|
{
|
||||||
|
MeterAddress = request.SubProtocolRequest.MeterAddress,
|
||||||
|
Password = request.SubProtocolRequest.Password,
|
||||||
|
ItemCode = request.SubProtocolRequest.ItemCode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t645PacketResponse != null)
|
||||||
|
{
|
||||||
|
dataUnit = t645PacketResponse.Data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string afnMethonCode = $"AFN{aFNStr}_Fn_Send";
|
||||||
|
if (T3761AFNHandlers != null && T3761AFNHandlers.TryGetValue(afnMethonCode
|
||||||
|
, out var handler))
|
||||||
|
{
|
||||||
|
builderResponse = handler(new Telemetry3761PacketRequest()
|
||||||
|
{
|
||||||
|
FocusAddress = request.FocusAddress,
|
||||||
|
Fn = fn,
|
||||||
|
Pn = request.Pn,
|
||||||
|
DataUnit = dataUnit,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builderResponse == null)
|
||||||
|
{
|
||||||
|
return new ProtocolBuildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = builderResponse.Adapt<ProtocolBuildResponse>();
|
||||||
|
result.IsSuccess = true;
|
||||||
|
|
||||||
|
return await Task.FromResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#region 上行命令
|
#region 上行命令
|
||||||
|
|
||||||
//68
|
//68
|
||||||
|
|||||||
@ -11,6 +11,7 @@ using JiShe.CollectBus.IoTDB.Interface;
|
|||||||
using JiShe.CollectBus.IoTDB.Model;
|
using JiShe.CollectBus.IoTDB.Model;
|
||||||
using JiShe.CollectBus.IoTDB.Options;
|
using JiShe.CollectBus.IoTDB.Options;
|
||||||
using JiShe.CollectBus.IoTDB.Provider;
|
using JiShe.CollectBus.IoTDB.Provider;
|
||||||
|
using JiShe.CollectBus.IotSystems.Ammeters;
|
||||||
using JiShe.CollectBus.IotSystems.PrepayModel;
|
using JiShe.CollectBus.IotSystems.PrepayModel;
|
||||||
using JiShe.CollectBus.Kafka.Attributes;
|
using JiShe.CollectBus.Kafka.Attributes;
|
||||||
using JiShe.CollectBus.Kafka.Internal;
|
using JiShe.CollectBus.Kafka.Internal;
|
||||||
|
|||||||
@ -23,11 +23,13 @@ using JiShe.CollectBus.IotSystems.MessageReceiveds;
|
|||||||
using Volo.Abp.Domain.Repositories;
|
using Volo.Abp.Domain.Repositories;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using Cassandra;
|
using Cassandra;
|
||||||
using JiShe.CollectBus.Interceptors;
|
using JiShe.CollectBus.Interceptors;
|
||||||
using JiShe.CollectBus.IotSystems.Protocols;
|
using JiShe.CollectBus.IotSystems.Protocols;
|
||||||
using TouchSocket.Core;
|
using TouchSocket.Core;
|
||||||
using Volo.Abp.Modularity;
|
using Volo.Abp.Modularity;
|
||||||
|
using JiShe.CollectBus.DynamicModule;
|
||||||
|
|
||||||
namespace JiShe.CollectBus.Samples;
|
namespace JiShe.CollectBus.Samples;
|
||||||
|
|
||||||
@ -39,18 +41,20 @@ public class TestAppService : CollectBusAppService
|
|||||||
private readonly ICassandraProvider _cassandraProvider;
|
private readonly ICassandraProvider _cassandraProvider;
|
||||||
private readonly IProtocolService _protocolService;
|
private readonly IProtocolService _protocolService;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly IDynamicModuleManager _dynamicModuleManager;
|
||||||
|
|
||||||
|
|
||||||
public TestAppService(
|
public TestAppService(
|
||||||
ILogger<TestAppService> logger,
|
ILogger<TestAppService> logger,
|
||||||
ICassandraRepository<MessageIssued, string> messageReceivedCassandraRepository,
|
ICassandraRepository<MessageIssued, string> messageReceivedCassandraRepository,
|
||||||
ICassandraProvider cassandraProvider, IProtocolService protocolService,IServiceProvider serviceProvider)
|
ICassandraProvider cassandraProvider, IProtocolService protocolService,IServiceProvider serviceProvider, IDynamicModuleManager dynamicModuleManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_messageReceivedCassandraRepository = messageReceivedCassandraRepository;
|
_messageReceivedCassandraRepository = messageReceivedCassandraRepository;
|
||||||
_cassandraProvider = cassandraProvider;
|
_cassandraProvider = cassandraProvider;
|
||||||
_protocolService = protocolService;
|
_protocolService = protocolService;
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
|
_dynamicModuleManager = dynamicModuleManager;
|
||||||
}
|
}
|
||||||
public async Task AddMessageOfCassandra()
|
public async Task AddMessageOfCassandra()
|
||||||
{
|
{
|
||||||
@ -146,6 +150,9 @@ public class TestAppService : CollectBusAppService
|
|||||||
// 重新加载插件方法
|
// 重新加载插件方法
|
||||||
public async Task ReloadPluginsAsync()
|
public async Task ReloadPluginsAsync()
|
||||||
{
|
{
|
||||||
//_serviceProvider.GetService<>()
|
var aa = Assembly.LoadFile(
|
||||||
|
@"D:\Codes\CollectBusV5\JiShe.CollectBus\web\JiShe.CollectBus.Host\bin\Debug\net8.0\Plugins\JiShe.CollectBus.Protocol.Test.dll");
|
||||||
|
var module = aa.GetTypes().First(a=> typeof(IAbpModule).IsAssignableFrom(a));
|
||||||
|
await _dynamicModuleManager.ReinitializeModuleAsync(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using JiShe.CollectBus.Application.Contracts;
|
using JiShe.CollectBus.Application.Contracts;
|
||||||
|
using JiShe.CollectBus.Common;
|
||||||
using JiShe.CollectBus.Common.BuildSendDatas;
|
using JiShe.CollectBus.Common.BuildSendDatas;
|
||||||
using JiShe.CollectBus.Common.Consts;
|
using JiShe.CollectBus.Common.Consts;
|
||||||
using JiShe.CollectBus.Common.DeviceBalanceControl;
|
using JiShe.CollectBus.Common.DeviceBalanceControl;
|
||||||
@ -7,6 +8,7 @@ using JiShe.CollectBus.Common.Enums;
|
|||||||
using JiShe.CollectBus.Common.Extensions;
|
using JiShe.CollectBus.Common.Extensions;
|
||||||
using JiShe.CollectBus.Common.Helpers;
|
using JiShe.CollectBus.Common.Helpers;
|
||||||
using JiShe.CollectBus.Common.Models;
|
using JiShe.CollectBus.Common.Models;
|
||||||
|
using JiShe.CollectBus.EnergySystems.Entities;
|
||||||
using JiShe.CollectBus.GatherItem;
|
using JiShe.CollectBus.GatherItem;
|
||||||
using JiShe.CollectBus.IoTDB.Context;
|
using JiShe.CollectBus.IoTDB.Context;
|
||||||
using JiShe.CollectBus.IoTDB.Interface;
|
using JiShe.CollectBus.IoTDB.Interface;
|
||||||
@ -19,14 +21,18 @@ using JiShe.CollectBus.IotSystems.Watermeter;
|
|||||||
using JiShe.CollectBus.Kafka.Internal;
|
using JiShe.CollectBus.Kafka.Internal;
|
||||||
using JiShe.CollectBus.Kafka.Producer;
|
using JiShe.CollectBus.Kafka.Producer;
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.Models;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.SendData;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Identity.Client;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using static System.Runtime.CompilerServices.RuntimeHelpers;
|
||||||
|
|
||||||
namespace JiShe.CollectBus.ScheduledMeterReading
|
namespace JiShe.CollectBus.ScheduledMeterReading
|
||||||
{
|
{
|
||||||
@ -40,8 +46,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
private readonly IProducerService _producerService;
|
private readonly IProducerService _producerService;
|
||||||
private readonly IRedisDataCacheService _redisDataCacheService;
|
private readonly IRedisDataCacheService _redisDataCacheService;
|
||||||
private readonly KafkaOptionConfig _kafkaOptions;
|
private readonly KafkaOptionConfig _kafkaOptions;
|
||||||
|
private readonly ServerApplicationOptions _applicationOptions;
|
||||||
private readonly IoTDBRuntimeContext _runtimeContext;
|
private readonly IoTDBRuntimeContext _runtimeContext;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IProtocolService _protocolService;
|
||||||
|
|
||||||
int pageSize = 3000;
|
int pageSize = 3000;
|
||||||
|
|
||||||
@ -51,8 +58,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
IRedisDataCacheService redisDataCacheService,
|
IRedisDataCacheService redisDataCacheService,
|
||||||
IIoTDbProvider dbProvider,
|
IIoTDbProvider dbProvider,
|
||||||
IoTDBRuntimeContext runtimeContext,
|
IoTDBRuntimeContext runtimeContext,
|
||||||
IServiceProvider serviceProvider,
|
IProtocolService protocolService,
|
||||||
IOptions<KafkaOptionConfig> kafkaOptions)
|
IOptions<KafkaOptionConfig> kafkaOptions,
|
||||||
|
IOptions<ServerApplicationOptions> applicationOptions)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_dbProvider = dbProvider;
|
_dbProvider = dbProvider;
|
||||||
@ -60,7 +68,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
_producerService = producerService;
|
_producerService = producerService;
|
||||||
_redisDataCacheService = redisDataCacheService;
|
_redisDataCacheService = redisDataCacheService;
|
||||||
_kafkaOptions = kafkaOptions.Value;
|
_kafkaOptions = kafkaOptions.Value;
|
||||||
_serviceProvider = serviceProvider;
|
_applicationOptions = applicationOptions.Value;
|
||||||
|
_protocolService = protocolService;
|
||||||
|
|
||||||
_runtimeContext.UseTableSessionPool = true;
|
_runtimeContext.UseTableSessionPool = true;
|
||||||
}
|
}
|
||||||
@ -109,6 +118,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
}
|
}
|
||||||
|
|
||||||
var currentTime = DateTime.Now;
|
var currentTime = DateTime.Now;
|
||||||
|
|
||||||
|
//定时抄读
|
||||||
foreach (var item in taskInfos)
|
foreach (var item in taskInfos)
|
||||||
{
|
{
|
||||||
var tasksToBeIssueModel = await FreeRedisProvider.Instance.GetAsync<TasksToBeIssueModel>(item);
|
var tasksToBeIssueModel = await FreeRedisProvider.Instance.GetAsync<TasksToBeIssueModel>(item);
|
||||||
@ -145,15 +156,15 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
timeDensity: timeDensity,
|
timeDensity: timeDensity,
|
||||||
nextTaskTime: currentTaskTime,
|
nextTaskTime: currentTaskTime,
|
||||||
meterType: MeterTypeEnum.Ammeter,
|
meterType: MeterTypeEnum.Ammeter,
|
||||||
taskCreateAction: (timeDensity, data, groupIndex, timestamps) =>
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
||||||
{
|
{
|
||||||
var tempTask = AmmerterCreatePublishTaskAction(timeDensity, data, groupIndex, timestamps);
|
var tempTask = await AmmerterCreatePublishTaskAction(timeDensity, data, groupIndex, timestamps);
|
||||||
if (tempTask == null || tempTask.Count <= 0)
|
if (tempTask == null || tempTask.Count <= 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"电表 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
_logger.LogWarning($"电表 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_dbProvider.BatchInsertAsync(metadata, tempTask);
|
_ = _dbProvider.BatchInsertAsync(metadata, tempTask);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (meteryType == MeterTypeEnum.WaterMeter.ToString())
|
else if (meteryType == MeterTypeEnum.WaterMeter.ToString())
|
||||||
@ -163,16 +174,16 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
timeDensity: timeDensity,
|
timeDensity: timeDensity,
|
||||||
nextTaskTime: currentTaskTime,
|
nextTaskTime: currentTaskTime,
|
||||||
meterType: MeterTypeEnum.WaterMeter,
|
meterType: MeterTypeEnum.WaterMeter,
|
||||||
taskCreateAction: (timeDensity, data, groupIndex, timestamps) =>
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
||||||
{
|
{
|
||||||
var tempTask = WatermeterCreatePublishTaskAction(timeDensity, data, groupIndex, timestamps);
|
var tempTask = await WatermeterCreatePublishTaskAction(timeDensity, data, groupIndex, timestamps);
|
||||||
|
|
||||||
if (tempTask == null || tempTask.Count <= 0)
|
if (tempTask == null || tempTask.Count <= 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"水表 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
_logger.LogWarning($"水表 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_dbProvider.BatchInsertAsync(metadata, tempTask);
|
_ = _dbProvider.BatchInsertAsync(metadata, tempTask);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -189,6 +200,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
tasksToBeIssueModel.NextTaskTime = currentTaskTime.CalculateNextCollectionTime(timeDensity);
|
tasksToBeIssueModel.NextTaskTime = currentTaskTime.CalculateNextCollectionTime(timeDensity);
|
||||||
await FreeRedisProvider.Instance.SetAsync(item, tasksToBeIssueModel);
|
await FreeRedisProvider.Instance.SetAsync(item, tasksToBeIssueModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//电表定时阀控任务处理。
|
||||||
|
//电表定时广播校时,一天一次。
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 电表采集处理
|
#region 电表采集处理
|
||||||
@ -275,9 +289,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
//根据采集频率分组,获得采集频率分组
|
//根据采集频率分组,获得采集频率分组
|
||||||
var meterInfoGroupByTimeDensity = meterInfos.GroupBy(d => d.TimeDensity);
|
var meterInfoGroupByTimeDensity = meterInfos.GroupBy(d => d.TimeDensity);
|
||||||
|
|
||||||
if (_kafkaOptions.FirstCollectionTime.HasValue == false)
|
if (_applicationOptions.FirstCollectionTime.HasValue == false)
|
||||||
{
|
{
|
||||||
_kafkaOptions.FirstCollectionTime = DateTime.Now;
|
_applicationOptions.FirstCollectionTime = DateTime.Now;
|
||||||
}
|
}
|
||||||
//先处理采集频率任务缓存
|
//先处理采集频率任务缓存
|
||||||
foreach (var item in meterInfoGroupByTimeDensity)
|
foreach (var item in meterInfoGroupByTimeDensity)
|
||||||
@ -286,7 +300,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
{
|
{
|
||||||
LastTaskTime = null,
|
LastTaskTime = null,
|
||||||
TimeDensity = item.Key,
|
TimeDensity = item.Key,
|
||||||
NextTaskTime = _kafkaOptions.FirstCollectionTime.Value.CalculateNextCollectionTime(item.Key),//使用首次采集时间作为下一次采集时间
|
NextTaskTime = _applicationOptions.FirstCollectionTime.Value.CalculateNextCollectionTime(item.Key),//使用首次采集时间作为下一次采集时间
|
||||||
};
|
};
|
||||||
|
|
||||||
//todo 首次采集时间节点到目前运行时间中漏采的时间点,可以考虑使用IoTDB的存储,利用时间序列处理。
|
//todo 首次采集时间节点到目前运行时间中漏采的时间点,可以考虑使用IoTDB的存储,利用时间序列处理。
|
||||||
@ -500,11 +514,20 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
/// <param name="groupIndex">集中器所在分组</param>
|
/// <param name="groupIndex">集中器所在分组</param>
|
||||||
/// <param name="timestamps">采集频率对应的时间戳</param>
|
/// <param name="timestamps">采集频率对应的时间戳</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private List<MeterReadingTelemetryPacketInfo> AmmerterCreatePublishTaskAction(int timeDensity, AmmeterInfo ammeterInfo, int groupIndex, DateTime timestamps)
|
private async Task<List<MeterReadingTelemetryPacketInfo>> AmmerterCreatePublishTaskAction(int timeDensity, AmmeterInfo ammeterInfo, int groupIndex, DateTime timestamps)
|
||||||
{
|
{
|
||||||
var currentTime = DateTime.Now;
|
var currentTime = DateTime.Now;
|
||||||
|
|
||||||
var handlerPacketBuilder = TelemetryPacketBuilder.AFNHandlersDictionary;
|
//根据电表型号获取协议插件
|
||||||
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(ammeterInfo.BrandType);
|
||||||
|
if (protocolPlugin == null)
|
||||||
|
{
|
||||||
|
//_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有找到对应的协议组件,-105");
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//todo 检查需要待补抄的电表的时间点信息,保存到需要待补抄的缓存中。如果此线程异常,该如何补偿?
|
//todo 检查需要待补抄的电表的时间点信息,保存到需要待补抄的缓存中。如果此线程异常,该如何补偿?
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(ammeterInfo.ItemCodes))
|
if (string.IsNullOrWhiteSpace(ammeterInfo.ItemCodes))
|
||||||
@ -601,43 +624,18 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemCodeArr = tempItem.Split('_');
|
//var itemCodeArr = tempItem.Split('_');
|
||||||
var aFNStr = itemCodeArr[0];
|
//var aFNStr = itemCodeArr[0];
|
||||||
var aFN = (AFN)aFNStr.HexToDec();
|
//var aFN = (AFN)aFNStr.HexToDec();
|
||||||
var fn = int.Parse(itemCodeArr[1]);
|
//var fn = int.Parse(itemCodeArr[1]);
|
||||||
TelemetryPacketResponse builderResponse = null;
|
|
||||||
if (ammeterInfo.AutomaticReport.Equals(1) && aFN == AFN.请求实时数据)
|
|
||||||
{
|
|
||||||
//实时数据
|
|
||||||
builderResponse = TelemetryPacketBuilder.AFN0C_Fn_Send(new TelemetryPacketRequest()
|
|
||||||
{
|
|
||||||
FocusAddress = ammeterInfo.FocusAddress,
|
|
||||||
Fn = fn,
|
|
||||||
Pn = ammeterInfo.MeteringCode
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string methonCode = $"AFN{aFNStr}_Fn_Send";
|
|
||||||
//特殊表暂不处理
|
|
||||||
if (handlerPacketBuilder != null && handlerPacketBuilder.TryGetValue(methonCode
|
|
||||||
, out var handler))
|
|
||||||
{
|
|
||||||
builderResponse = handler(new TelemetryPacketRequest()
|
|
||||||
{
|
|
||||||
FocusAddress = ammeterInfo.FocusAddress,
|
|
||||||
Fn = fn,
|
|
||||||
Pn = ammeterInfo.MeteringCode
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogWarning($"{nameof(AmmerterCreatePublishTaskAction)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{tempItem}无效编码。");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//TODO:特殊表
|
|
||||||
|
|
||||||
|
//TODO:特殊表
|
||||||
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
||||||
|
{
|
||||||
|
FocusAddress = ammeterInfo.FocusAddress,
|
||||||
|
Pn = ammeterInfo.MeteringCode,
|
||||||
|
ItemCode = tempItem,
|
||||||
|
});
|
||||||
if (builderResponse == null || builderResponse.Data.Length <= 0)
|
if (builderResponse == null || builderResponse.Data.Length <= 0)
|
||||||
{
|
{
|
||||||
//_logger.LogWarning($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{tempItem}未能正确获取报文。");
|
//_logger.LogWarning($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{tempItem}未能正确获取报文。");
|
||||||
@ -645,7 +643,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string taskMark = CommonHelper.GetTaskMark((int)aFN, fn, ammeterInfo.MeteringCode, builderResponse.MSA);
|
string taskMark = CommonHelper.GetTaskMark(builderResponse.AFn, builderResponse.Fn, ammeterInfo.MeteringCode, builderResponse.MSA, builderResponse.Seq);
|
||||||
var meterReadingRecords = new MeterReadingTelemetryPacketInfo()
|
var meterReadingRecords = new MeterReadingTelemetryPacketInfo()
|
||||||
{
|
{
|
||||||
SystemName = SystemType,
|
SystemName = SystemType,
|
||||||
@ -657,9 +655,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
PendingCopyReadTime = timestamps,
|
PendingCopyReadTime = timestamps,
|
||||||
CreationTime = currentTime,
|
CreationTime = currentTime,
|
||||||
MeterAddress = ammeterInfo.AmmerterAddress,
|
MeterAddress = ammeterInfo.AmmerterAddress,
|
||||||
AFN = (int)aFN,
|
AFN = builderResponse.AFn,
|
||||||
Fn = fn,
|
Fn = builderResponse.Fn,
|
||||||
//Seq = builderResponse.Seq,
|
Seq = builderResponse.Seq,
|
||||||
MSA = builderResponse.MSA,
|
MSA = builderResponse.MSA,
|
||||||
ItemCode = tempItem,
|
ItemCode = tempItem,
|
||||||
TaskMark = taskMark,
|
TaskMark = taskMark,
|
||||||
@ -736,9 +734,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
|
|
||||||
//根据采集频率分组,获得采集频率分组
|
//根据采集频率分组,获得采集频率分组
|
||||||
var meterInfoGroupByTimeDensity = meterInfos.GroupBy(d => d.TimeDensity);
|
var meterInfoGroupByTimeDensity = meterInfos.GroupBy(d => d.TimeDensity);
|
||||||
if (_kafkaOptions.FirstCollectionTime.HasValue == false)
|
if (_applicationOptions.FirstCollectionTime.HasValue == false)
|
||||||
{
|
{
|
||||||
_kafkaOptions.FirstCollectionTime = DateTime.Now;
|
_applicationOptions.FirstCollectionTime = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
//先处理采集频率任务缓存
|
//先处理采集频率任务缓存
|
||||||
@ -748,7 +746,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
{
|
{
|
||||||
LastTaskTime = null,
|
LastTaskTime = null,
|
||||||
TimeDensity = item.Key,
|
TimeDensity = item.Key,
|
||||||
NextTaskTime = _kafkaOptions.FirstCollectionTime.Value.CalculateNextCollectionTime(item.Key),//使用首次采集时间作为下一次采集时间
|
NextTaskTime = _applicationOptions.FirstCollectionTime.Value.CalculateNextCollectionTime(item.Key),//使用首次采集时间作为下一次采集时间
|
||||||
};
|
};
|
||||||
|
|
||||||
//todo 首次采集时间节点到目前运行时间中漏采的时间点,可以考虑使用IoTDB的存储,利用时间序列处理。
|
//todo 首次采集时间节点到目前运行时间中漏采的时间点,可以考虑使用IoTDB的存储,利用时间序列处理。
|
||||||
@ -851,10 +849,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
/// <param name="groupIndex">集中器所在分组</param>
|
/// <param name="groupIndex">集中器所在分组</param>
|
||||||
/// <param name="timestamps">时间格式的任务批次名称</param>
|
/// <param name="timestamps">时间格式的任务批次名称</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private List<MeterReadingTelemetryPacketInfo> WatermeterCreatePublishTaskAction(int timeDensity
|
private async Task<List<MeterReadingTelemetryPacketInfo>> WatermeterCreatePublishTaskAction(int timeDensity
|
||||||
, WatermeterInfo watermeter, int groupIndex, DateTime timestamps)
|
, WatermeterInfo watermeter, int groupIndex, DateTime timestamps)
|
||||||
{
|
{
|
||||||
var handlerPacketBuilder = TelemetryPacketBuilder.AFNHandlersDictionary;
|
|
||||||
var currentTime = DateTime.Now;
|
var currentTime = DateTime.Now;
|
||||||
|
|
||||||
string typeName;
|
string typeName;
|
||||||
@ -912,10 +909,12 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
tempCodes = new List<string>() { "10_1" };
|
tempCodes = new List<string>() { "10_1" };
|
||||||
}
|
}
|
||||||
|
|
||||||
var protocolPlugin = _serviceProvider.GetKeyedService<IProtocolPlugin>("StandardProtocolPlugin");
|
//根据表型号获取协议插件
|
||||||
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(watermeter.Code);
|
||||||
if (protocolPlugin == null)
|
if (protocolPlugin == null)
|
||||||
{
|
{
|
||||||
_logger.LogError("协议不存在!");
|
//_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有找到对应的协议组件,-105");
|
||||||
|
//return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var tempItem in tempCodes)
|
foreach (var tempItem in tempCodes)
|
||||||
@ -931,39 +930,57 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemCodeArr = tempItem.Split('_');
|
//var itemCodeArr = tempItem.Split('_');
|
||||||
var aFNStr = itemCodeArr[0];
|
//var aFNStr = itemCodeArr[0];
|
||||||
var aFN = (AFN)aFNStr.HexToDec();
|
//var aFN = (AFN)aFNStr.HexToDec();
|
||||||
var fn = int.Parse(itemCodeArr[1]);
|
//var fn = int.Parse(itemCodeArr[1]);
|
||||||
TelemetryPacketResponse builderResponse = null;
|
//TelemetryPacketResponse builderResponse = null;
|
||||||
|
|
||||||
string methonCode = $"AFN{aFNStr}_Fn_Send";
|
//string methonCode = $"AFN{aFNStr}_Fn_Send";
|
||||||
//特殊表暂不处理
|
////特殊表暂不处理
|
||||||
if (handlerPacketBuilder != null && handlerPacketBuilder.TryGetValue(methonCode
|
//if (handlerPacketBuilder != null && handlerPacketBuilder.TryGetValue(methonCode
|
||||||
, out var handler))
|
// , out var handler))
|
||||||
|
//{
|
||||||
|
// builderResponse = handler(new TelemetryPacketRequest()
|
||||||
|
// {
|
||||||
|
// FocusAddress = watermeter.FocusAddress,
|
||||||
|
// Fn = fn,
|
||||||
|
// Pn = watermeter.MeteringCode,
|
||||||
|
// DataUnit = Build188SendData.Build188WaterMeterReadingSendDataUnit(watermeter.Address),
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// _logger.LogWarning($"{nameof(WatermeterCreatePublishTaskAction)} 集中器{watermeter.FocusAddress}的水表{watermeter.Name}采集项{tempItem}无效编码。");
|
||||||
|
// continue;
|
||||||
|
//}
|
||||||
|
|
||||||
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
||||||
{
|
{
|
||||||
builderResponse = handler(new TelemetryPacketRequest()
|
FocusAddress = watermeter.FocusAddress,
|
||||||
|
Pn = watermeter.MeteringCode,
|
||||||
|
ItemCode = tempItem,
|
||||||
|
SubProtocolRequest = new SubProtocolBuildRequest()
|
||||||
{
|
{
|
||||||
FocusAddress = watermeter.FocusAddress,
|
MeterAddress = watermeter.MeterAddress,
|
||||||
Fn = fn,
|
Password = watermeter.Password,
|
||||||
Pn = watermeter.MeteringCode,
|
ItemCode = tempItem,
|
||||||
DataUnit = Build188SendData.Build188WaterMeterReadingSendDataUnit(watermeter.Address),
|
}
|
||||||
});
|
});
|
||||||
}
|
if (builderResponse == null || builderResponse.Data.Length <= 0)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"{nameof(WatermeterCreatePublishTaskAction)} 集中器{watermeter.FocusAddress}的电表{watermeter.Name}采集项{tempItem}无效编码。");
|
//_logger.LogWarning($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{tempItem}未能正确获取报文。");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builderResponse == null || builderResponse.Data.Length <= 0)
|
if (builderResponse == null || builderResponse.Data.Length <= 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning($"{nameof(WatermeterCreatePublishTaskAction)} 集中器{watermeter.FocusAddress}的电表{watermeter.Name}采集项{tempItem}未能正确获取报文。");
|
_logger.LogWarning($"{nameof(WatermeterCreatePublishTaskAction)} 集中器{watermeter.FocusAddress}的水表{watermeter.Name}采集项{tempItem}未能正确获取报文。");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string taskMark = CommonHelper.GetTaskMark((int)aFN, fn, watermeter.MeteringCode, builderResponse.MSA);
|
string taskMark = CommonHelper.GetTaskMark(builderResponse.AFn, builderResponse.Fn, watermeter.MeteringCode, builderResponse.MSA, builderResponse.Seq);
|
||||||
var meterReadingRecords = new MeterReadingTelemetryPacketInfo()
|
var meterReadingRecords = new MeterReadingTelemetryPacketInfo()
|
||||||
{
|
{
|
||||||
SystemName = SystemType,
|
SystemName = SystemType,
|
||||||
@ -975,9 +992,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
PendingCopyReadTime = timestamps,
|
PendingCopyReadTime = timestamps,
|
||||||
CreationTime = currentTime,
|
CreationTime = currentTime,
|
||||||
MeterAddress = watermeter.MeterAddress,
|
MeterAddress = watermeter.MeterAddress,
|
||||||
AFN = (int)aFN,
|
AFN = builderResponse.AFn,
|
||||||
Fn = fn,
|
Fn = builderResponse.Fn,
|
||||||
//Seq = builderResponse.Seq,
|
Seq = builderResponse.Seq,
|
||||||
MSA = builderResponse.MSA,
|
MSA = builderResponse.MSA,
|
||||||
ItemCode = tempItem,
|
ItemCode = tempItem,
|
||||||
TaskMark = taskMark,
|
TaskMark = taskMark,
|
||||||
@ -1102,8 +1119,6 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
bool hasNext;
|
bool hasNext;
|
||||||
var stopwatch = Stopwatch.StartNew();
|
var stopwatch = Stopwatch.StartNew();
|
||||||
|
|
||||||
var ddd = _runtimeContext.UseTableSessionPool;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
options.PageIndex = pageNumber++;
|
options.PageIndex = pageNumber++;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using JiShe.CollectBus.Application.Contracts;
|
using JiShe.CollectBus.Application.Contracts;
|
||||||
|
using JiShe.CollectBus.Common;
|
||||||
using JiShe.CollectBus.Common.BuildSendDatas;
|
using JiShe.CollectBus.Common.BuildSendDatas;
|
||||||
using JiShe.CollectBus.Common.Consts;
|
using JiShe.CollectBus.Common.Consts;
|
||||||
using JiShe.CollectBus.Common.DeviceBalanceControl;
|
using JiShe.CollectBus.Common.DeviceBalanceControl;
|
||||||
@ -16,6 +17,8 @@ using JiShe.CollectBus.IotSystems.Watermeter;
|
|||||||
using JiShe.CollectBus.Kafka.Internal;
|
using JiShe.CollectBus.Kafka.Internal;
|
||||||
using JiShe.CollectBus.Kafka.Producer;
|
using JiShe.CollectBus.Kafka.Producer;
|
||||||
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
using JiShe.CollectBus.Protocol.Contracts.Interfaces;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.Models;
|
||||||
|
using JiShe.CollectBus.Protocol.Contracts.SendData;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -38,28 +41,30 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
string serverTagName = string.Empty;
|
string serverTagName = string.Empty;
|
||||||
private readonly ILogger<BasicScheduledMeterReadingService> _logger;
|
private readonly ILogger<BasicScheduledMeterReadingService> _logger;
|
||||||
private readonly IIoTDbProvider _dbProvider;
|
private readonly IIoTDbProvider _dbProvider;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IProtocolService _protocolService;
|
||||||
|
|
||||||
public EnergySystemScheduledMeterReadingService(
|
public EnergySystemScheduledMeterReadingService(
|
||||||
ILogger<EnergySystemScheduledMeterReadingService> logger,
|
ILogger<EnergySystemScheduledMeterReadingService> logger,
|
||||||
IIoTDbProvider dbProvider,
|
IIoTDbProvider dbProvider,
|
||||||
IOptions<KafkaOptionConfig> kafkaOptions,
|
IOptions<KafkaOptionConfig> kafkaOptions,
|
||||||
|
IOptions<ServerApplicationOptions> applicationOptions,
|
||||||
IoTDBRuntimeContext runtimeContext,
|
IoTDBRuntimeContext runtimeContext,
|
||||||
IProducerService producerService,
|
IProducerService producerService,
|
||||||
IServiceProvider serviceProvider,
|
IProtocolService protocolService,
|
||||||
IRedisDataCacheService redisDataCacheService)
|
IRedisDataCacheService redisDataCacheService)
|
||||||
: base(logger,
|
: base(logger,
|
||||||
producerService,
|
producerService,
|
||||||
redisDataCacheService,
|
redisDataCacheService,
|
||||||
dbProvider,
|
dbProvider,
|
||||||
runtimeContext,
|
runtimeContext,
|
||||||
serviceProvider,
|
protocolService,
|
||||||
kafkaOptions)
|
kafkaOptions,
|
||||||
|
applicationOptions)
|
||||||
{
|
{
|
||||||
serverTagName = kafkaOptions.Value.ServerTagName;
|
serverTagName = applicationOptions.Value.ServerTagName;
|
||||||
_dbProvider = dbProvider;
|
_dbProvider = dbProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_serviceProvider = serviceProvider;
|
_protocolService = protocolService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed override string SystemType => SystemTypeConst.Energy;
|
public sealed override string SystemType => SystemTypeConst.Energy;
|
||||||
@ -179,13 +184,12 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override async Task AmmeterScheduledAutoValveControl()
|
public override async Task AmmeterScheduledAutoValveControl()
|
||||||
{
|
{
|
||||||
var handlerPacketBuilder = TelemetryPacketBuilder.AFNHandlersDictionary;
|
|
||||||
|
|
||||||
var currentTime = DateTime.Now;
|
var currentTime = DateTime.Now;
|
||||||
string currentTimeStr = $"{currentTime:HH:mm}";
|
string currentTimeStr = $"{currentTime:HH:mm}";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
//获取电表阀控配置
|
||||||
var settingInfos = await GetAmmeterAutoValveControlSetting(currentTimeStr);
|
var settingInfos = await GetAmmeterAutoValveControlSetting(currentTimeStr);
|
||||||
|
|
||||||
if (settingInfos == null || settingInfos.Count <= 0)
|
if (settingInfos == null || settingInfos.Count <= 0)
|
||||||
@ -226,16 +230,22 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
//获取对应的缓存电表信息
|
//获取对应的缓存电表信息
|
||||||
var ammeterInfo = ammeterInfos.First();
|
var ammeterInfo = ammeterInfos.First();
|
||||||
bool tripStateResult = false;
|
bool tripStateResult = false;
|
||||||
|
string subItemCode = string.Empty;
|
||||||
if (settingInfo.TripType.Equals("on"))
|
if (settingInfo.TripType.Equals("on"))
|
||||||
{
|
{
|
||||||
ammeterInfo.TripState = 0;
|
ammeterInfo.TripState = 0;
|
||||||
tripStateResult = true;
|
tripStateResult = true;
|
||||||
|
subItemCode = T645PacketItemCodeConst.C1C01C;
|
||||||
|
if (ammeterInfo.TypeName != 1)
|
||||||
|
{
|
||||||
|
subItemCode = T645PacketItemCodeConst.C1C01B;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (settingInfo.TripType.Equals("off"))
|
else if (settingInfo.TripType.Equals("off"))
|
||||||
{
|
{
|
||||||
ammeterInfo.TripState = 1;
|
ammeterInfo.TripState = 1;
|
||||||
tripStateResult = false;
|
tripStateResult = false;
|
||||||
|
subItemCode = T645PacketItemCodeConst.C1C01A;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -243,44 +253,30 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var protocolPlugin = _serviceProvider.GetKeyedService<IProtocolPlugin>("StandardProtocolPlugin");
|
var temCode = "10_01_";
|
||||||
|
|
||||||
|
//根据电表型号获取协议插件
|
||||||
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(ammeterInfo.BrandType);
|
||||||
if (protocolPlugin == null)
|
if (protocolPlugin == null)
|
||||||
{
|
{
|
||||||
_logger.LogError("协议不存在!");
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有找到对应的协议组件,-105");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var temCode = "10_98";
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
||||||
var itemCodeArr = temCode.Split('_');
|
|
||||||
var aFNStr = itemCodeArr[0];
|
|
||||||
var aFN = (AFN)(aFNStr.HexToDec());
|
|
||||||
var fn = int.Parse(itemCodeArr[1]);
|
|
||||||
TelemetryPacketResponse builderResponse = null;
|
|
||||||
string methonCode = $"AFN{aFNStr}_Fn_Send";
|
|
||||||
//特殊表暂不处理
|
|
||||||
if (handlerPacketBuilder != null && handlerPacketBuilder.TryGetValue(methonCode
|
|
||||||
, out var handler))
|
|
||||||
{
|
{
|
||||||
builderResponse = handler(new TelemetryPacketRequest()
|
FocusAddress = ammeterInfo.FocusAddress,
|
||||||
|
Pn = ammeterInfo.MeteringCode,
|
||||||
|
ItemCode = temCode,
|
||||||
|
SubProtocolRequest = new SubProtocolBuildRequest()
|
||||||
{
|
{
|
||||||
FocusAddress = ammeterInfo.FocusAddress,
|
MeterAddress = ammeterInfo.AmmerterAddress,
|
||||||
Fn = fn,
|
Password = ammeterInfo.Password,
|
||||||
Pn = ammeterInfo.MeteringCode,
|
ItemCode = subItemCode,
|
||||||
DataUnit = Build645SendData.BuildAmmeterValveControlSendDataUnit(ammeterInfo.AmmerterAddress, "", ammeterInfo.Password, tripStateResult),//生成阀控报文
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{temCode}无效编码,-103");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (builderResponse == null)
|
string taskMark = CommonHelper.GetTaskMark(builderResponse.AFn, builderResponse.Fn, ammeterInfo.MeteringCode, builderResponse.MSA, builderResponse.Seq);
|
||||||
{
|
|
||||||
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{temCode}报文构建失败,-104");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string taskMark = CommonHelper.GetTaskMark((int)aFN, fn, ammeterInfo.MeteringCode, builderResponse.MSA);
|
|
||||||
var meterReadingRecords = new MeterReadingTelemetryPacketInfo()
|
var meterReadingRecords = new MeterReadingTelemetryPacketInfo()
|
||||||
{
|
{
|
||||||
SystemName = SystemType,
|
SystemName = SystemType,
|
||||||
@ -292,9 +288,9 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
PendingCopyReadTime = currentTime,
|
PendingCopyReadTime = currentTime,
|
||||||
CreationTime = currentTime,
|
CreationTime = currentTime,
|
||||||
MeterAddress = ammeterInfo.AmmerterAddress,
|
MeterAddress = ammeterInfo.AmmerterAddress,
|
||||||
AFN = (int)aFN,
|
AFN = builderResponse.AFn,
|
||||||
Fn = fn,
|
Fn = builderResponse.Fn,
|
||||||
//Seq = builderResponse.Seq,
|
Seq = builderResponse.Seq,
|
||||||
MSA = builderResponse.MSA,
|
MSA = builderResponse.MSA,
|
||||||
ItemCode = temCode,
|
ItemCode = temCode,
|
||||||
TaskMark = taskMark,
|
TaskMark = taskMark,
|
||||||
@ -310,7 +306,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
}
|
}
|
||||||
if (taskList == null || taskList.Count <= 0)
|
if (taskList == null || taskList.Count <= 0)
|
||||||
{
|
{
|
||||||
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有自动阀控任务生成,-105");
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有自动阀控任务生成,-106");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,9 +330,6 @@ namespace JiShe.CollectBus.ScheduledMeterReading
|
|||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
throw new NotImplementedException($"{nameof(GetAmmeterInfoList)}请根据不同系统类型进行实现");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -82,6 +82,7 @@ namespace JiShe.CollectBus.Subscribers
|
|||||||
[KafkaSubscribe(ProtocolConst.AmmeterSubscriberWorkerAutoValveControlIssuedEventName)]
|
[KafkaSubscribe(ProtocolConst.AmmeterSubscriberWorkerAutoValveControlIssuedEventName)]
|
||||||
public async Task<ISubscribeAck> AmmeterScheduledAutoValveControl(MeterReadingTelemetryPacketInfo receivedMessage)
|
public async Task<ISubscribeAck> AmmeterScheduledAutoValveControl(MeterReadingTelemetryPacketInfo receivedMessage)
|
||||||
{
|
{
|
||||||
|
//todo 如果是时段自动阀控,需要检查当前的时间,如果时间在自动阀控时间段内,则发送自动阀控报文,否则不发送,尤其是消息队列阻塞或者延时过长的时候。以免造成生产事故。
|
||||||
_logger.LogInformation("电表自动阀控下行消息消费队列开始处理");
|
_logger.LogInformation("电表自动阀控下行消息消费队列开始处理");
|
||||||
return await SendMessagesAsync(receivedMessage);
|
return await SendMessagesAsync(receivedMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,10 +104,10 @@ namespace JiShe.CollectBus.IotSystems.MeterReadingRecords
|
|||||||
[FIELDColumn]
|
[FIELDColumn]
|
||||||
public string ItemCode { get; set; }
|
public string ItemCode { get; set; }
|
||||||
|
|
||||||
///// <summary>
|
/// <summary>
|
||||||
///// 帧序列域SEQ
|
/// 帧序列域 SEQ
|
||||||
///// </summary>
|
/// </summary>
|
||||||
//public required Seq Seq { get; set; }
|
public int Seq { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 地址域A3的主站地址MSA
|
/// 地址域A3的主站地址MSA
|
||||||
|
|||||||
@ -69,6 +69,7 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
|
|||||||
var strP = password.StrAddSpan().StrReverseOrder();
|
var strP = password.StrAddSpan().StrReverseOrder();
|
||||||
var strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + code + " 00 " + strDate;
|
var strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + code + " 00 " + strDate;
|
||||||
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
|
var dataUnit = strSJY.Replace(" ", "").StringToPairs();
|
||||||
|
|
||||||
var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit);
|
var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit);
|
||||||
return dataList;
|
return dataList;
|
||||||
|
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
using JiShe.CollectBus.Common.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace JiShe.CollectBus.Common.BuildSendDatas
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 报文构建返回结果
|
|
||||||
/// </summary>
|
|
||||||
public class TelemetryPacketResponse
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 帧序列域SEQ
|
|
||||||
/// </summary>
|
|
||||||
public required Seq Seq { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 地址域A3的主站地址MSA
|
|
||||||
/// </summary>
|
|
||||||
public int MSA { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 报文体
|
|
||||||
/// </summary>
|
|
||||||
public required byte[] Data { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.Common.Consts
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// T645报文项编码
|
||||||
|
/// </summary>
|
||||||
|
public class T645PacketItemCodeConst
|
||||||
|
{
|
||||||
|
#region 跳合闸、报警、保电
|
||||||
|
/// <summary>
|
||||||
|
/// 跳闸
|
||||||
|
/// </summary>
|
||||||
|
public const string C1C01A = "1C_1A";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单相合闸
|
||||||
|
/// </summary>
|
||||||
|
public const string C1C01B = "1C_1B";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 三相合闸
|
||||||
|
/// </summary>
|
||||||
|
public const string C1C01C = "1C_1C";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 触发报警
|
||||||
|
/// </summary>
|
||||||
|
public const string C1C02A = "1C_2A";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报警解除
|
||||||
|
/// </summary>
|
||||||
|
public const string C1C02B = "1C_2B";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保电开始
|
||||||
|
/// </summary>
|
||||||
|
public const string C1C03A = "1C_3A";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保电结束
|
||||||
|
/// </summary>
|
||||||
|
public const string C1C03B = "1C_3B";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 广播校时
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 广播校时
|
||||||
|
/// </summary>
|
||||||
|
public const string C08 = "08";
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -768,10 +768,11 @@ namespace JiShe.CollectBus.Common.Helpers
|
|||||||
/// <param name="fn"></param>
|
/// <param name="fn"></param>
|
||||||
/// <param name="pn"></param>
|
/// <param name="pn"></param>
|
||||||
/// <param name="msa"></param>
|
/// <param name="msa"></param>
|
||||||
|
/// <param name="seq"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetTaskMark(int afn, int fn, int pn, int msa)
|
public static string GetTaskMark(int afn, int fn, int pn, int msa,int seq)
|
||||||
{
|
{
|
||||||
var makstr = $"{afn.ToString().PadLeft(2, '0')}{fn.ToString().PadLeft(2, '0')}{pn.ToString().PadLeft(2, '0')}";
|
var makstr = $"{afn.ToString().PadLeft(2, '0')}{fn.ToString().PadLeft(2, '0')}{pn.ToString().PadLeft(2, '0')}{msa.ToString().PadLeft(2, '0')}{seq.ToString().PadLeft(2, '0')}";
|
||||||
|
|
||||||
return makstr;// Convert.ToInt32(makstr) << 32 | msa;
|
return makstr;// Convert.ToInt32(makstr) << 32 | msa;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
namespace JiShe.CollectBus.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 服务器应用配置
|
||||||
|
/// </summary>
|
||||||
|
public class ServerApplicationOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 服务器标识
|
||||||
|
/// </summary>
|
||||||
|
public required string ServerTagName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 首次采集时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? FirstCollectionTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自动验证时间
|
||||||
|
/// </summary>
|
||||||
|
public required string AutomaticVerificationTime { get; set;}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,182 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Volo.Abp;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Modularity;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.DynamicModule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 动态模块管理器的实现
|
||||||
|
/// </summary>
|
||||||
|
public class DynamicModuleManager : IDynamicModuleManager, ISingletonDependency
|
||||||
|
{
|
||||||
|
private readonly IModuleContainer _moduleContainer;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public DynamicModuleManager(
|
||||||
|
IModuleContainer moduleContainer,
|
||||||
|
IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_moduleContainer = moduleContainer;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type[] GetRegisteredModuleTypes()
|
||||||
|
{
|
||||||
|
return _moduleContainer.Modules.Select(m => m.Type).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitializeModuleAsync(Type moduleType)
|
||||||
|
{
|
||||||
|
//if (!typeof(IAbpModule).IsAssignableFrom(moduleType))
|
||||||
|
//{
|
||||||
|
// throw new ArgumentException($"指定的类型 {moduleType.FullName} 不是有效的ABP模块类型", nameof(moduleType));
|
||||||
|
//}
|
||||||
|
|
||||||
|
//var module = (IAbpModule)Activator.CreateInstance(moduleType);
|
||||||
|
|
||||||
|
//// 配置服务
|
||||||
|
//var configureServicesMethod = moduleType.GetMethod("ConfigureServices",
|
||||||
|
// BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
|
||||||
|
|
||||||
|
//if (configureServicesMethod != null)
|
||||||
|
//{
|
||||||
|
// var serviceConfigurationContext = CreateServiceConfigurationContext();
|
||||||
|
// configureServicesMethod.Invoke(module, new object[] { serviceConfigurationContext });
|
||||||
|
//}
|
||||||
|
|
||||||
|
//await CallModuleMethodAsync(module, "OnApplicationInitializationAsync", new object[] { new ApplicationInitializationContext(_serviceProvider) });
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ReinitializeModuleAsync(Type moduleType)
|
||||||
|
{
|
||||||
|
if (!typeof(IAbpModule).IsAssignableFrom(moduleType))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"指定的类型 {moduleType.FullName} 不是有效的ABP模块类型", nameof(moduleType));
|
||||||
|
}
|
||||||
|
|
||||||
|
var moduleDescriptor = _moduleContainer.Modules.FirstOrDefault(m => m.Type.Name == moduleType.Name);
|
||||||
|
if (moduleDescriptor == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"找不到类型为 {moduleType.FullName} 的模块");
|
||||||
|
}
|
||||||
|
|
||||||
|
var module = moduleDescriptor.Instance;
|
||||||
|
|
||||||
|
await CallModuleMethodAsync(module, "OnApplicationShutdown", new object[] { new ApplicationShutdownContext(_serviceProvider) });
|
||||||
|
//var configureServicesMethod = moduleType.GetMethod("ConfigureServices",
|
||||||
|
// BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
|
||||||
|
|
||||||
|
//if (configureServicesMethod != null)
|
||||||
|
//{
|
||||||
|
// var serviceConfigurationContext = CreateServiceConfigurationContext();
|
||||||
|
// configureServicesMethod.Invoke(module, new object[] { serviceConfigurationContext });
|
||||||
|
//}
|
||||||
|
await CallModuleMethodAsync(module, "OnApplicationInitializationAsync", new object[] { new ApplicationInitializationContext(_serviceProvider) });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UnloadModuleAsync(Type moduleType)
|
||||||
|
{
|
||||||
|
if (!typeof(IAbpModule).IsAssignableFrom(moduleType))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"指定的类型 {moduleType.FullName} 不是有效的ABP模块类型", nameof(moduleType));
|
||||||
|
}
|
||||||
|
|
||||||
|
var moduleDescriptor = _moduleContainer.Modules.FirstOrDefault(m => m.Type.Name == moduleType.Name);
|
||||||
|
if (moduleDescriptor == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"找不到类型为 {moduleType.FullName} 的模块");
|
||||||
|
}
|
||||||
|
|
||||||
|
var module = moduleDescriptor.Instance;
|
||||||
|
|
||||||
|
await CallModuleMethodAsync(module, "OnApplicationShutdown", new object[] { new ApplicationShutdownContext(_serviceProvider) });
|
||||||
|
moduleDescriptor.GetType().GetProperty("IsUnloaded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?
|
||||||
|
.SetValue(moduleDescriptor, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsModuleLoaded(Type moduleType)
|
||||||
|
{
|
||||||
|
var moduleDescriptor = _moduleContainer.Modules.FirstOrDefault(m => m.Type == moduleType);
|
||||||
|
if (moduleDescriptor == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查模块是否已被标记为卸载
|
||||||
|
var isUnloaded = (bool?)moduleDescriptor.GetType().GetProperty("IsUnloaded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?
|
||||||
|
.GetValue(moduleDescriptor) ?? false;
|
||||||
|
|
||||||
|
return !isUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type GetModuleTypeByName(string moduleName)
|
||||||
|
{
|
||||||
|
return _moduleContainer.Modules
|
||||||
|
.FirstOrDefault(m => m.Type.Name == moduleName || m.Type.FullName == moduleName)?
|
||||||
|
.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CallModuleMethodAsync(IAbpModule module, string methodName, object[] parameters)
|
||||||
|
{
|
||||||
|
var method = module.GetType().GetMethod(methodName);
|
||||||
|
if (method == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.ReturnType == typeof(Task))
|
||||||
|
{
|
||||||
|
await (Task)method.Invoke(module, parameters);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
method.Invoke(module, parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceConfigurationContext CreateServiceConfigurationContext()
|
||||||
|
{
|
||||||
|
// 反射获取内部构造函数
|
||||||
|
var contextType = typeof(ServiceConfigurationContext);
|
||||||
|
var constructor = contextType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault();
|
||||||
|
|
||||||
|
if (constructor != null)
|
||||||
|
{
|
||||||
|
// 创建新的服务集合并添加现有服务
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
foreach (var service in ((IServiceCollection)_serviceProvider.GetService<IServiceCollection>()) ?? new ServiceCollection())
|
||||||
|
{
|
||||||
|
services.Add(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ServiceConfigurationContext)constructor.Invoke(new object[] { services });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果反射失败,使用备选方案
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
var context = Activator.CreateInstance(contextType, bindingFlags, null, null, null);
|
||||||
|
|
||||||
|
var servicesProperty = contextType.GetProperty("Services");
|
||||||
|
servicesProperty?.SetValue(context, services);
|
||||||
|
|
||||||
|
return (ServiceConfigurationContext)context;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("无法创建ServiceConfigurationContext。这可能是由于与ABP框架版本不兼容造成的。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace JiShe.CollectBus.DynamicModule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 提供动态管理ABP模块的功能
|
||||||
|
/// </summary>
|
||||||
|
public interface IDynamicModuleManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取已注册的模块类型
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>当前应用程序中已注册的所有模块类型</returns>
|
||||||
|
Type[] GetRegisteredModuleTypes();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重新初始化指定的模块
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="moduleType">要重新初始化的模块类型</param>
|
||||||
|
/// <returns>表示异步操作的任务</returns>
|
||||||
|
Task ReinitializeModuleAsync(Type moduleType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 卸载指定的模块
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="moduleType">要卸载的模块类型</param>
|
||||||
|
/// <returns>表示异步操作的任务</returns>
|
||||||
|
Task UnloadModuleAsync(Type moduleType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查模块是否已加载
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="moduleType">要检查的模块类型</param>
|
||||||
|
/// <returns>如果模块已加载,则为true;否则为false</returns>
|
||||||
|
bool IsModuleLoaded(Type moduleType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据模块名称获取模块类型
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="moduleName">模块名称</param>
|
||||||
|
/// <returns>模块类型,如果找不到则为null</returns>
|
||||||
|
Type GetModuleTypeByName(string moduleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,10 @@
|
|||||||
using Hangfire;
|
using Hangfire;
|
||||||
using HealthChecks.UI.Client;
|
using HealthChecks.UI.Client;
|
||||||
|
using JiShe.CollectBus.Common;
|
||||||
using JiShe.CollectBus.Host.Extensions;
|
using JiShe.CollectBus.Host.Extensions;
|
||||||
using JiShe.CollectBus.Host.HealthChecks;
|
using JiShe.CollectBus.Host.HealthChecks;
|
||||||
using JiShe.CollectBus.Host.Swaggers;
|
using JiShe.CollectBus.Host.Swaggers;
|
||||||
|
using JiShe.CollectBus.IoTDB.Options;
|
||||||
using JiShe.CollectBus.MongoDB;
|
using JiShe.CollectBus.MongoDB;
|
||||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||||
using Swashbuckle.AspNetCore.SwaggerUI;
|
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||||
@ -50,6 +52,12 @@ namespace JiShe.CollectBus.Host
|
|||||||
ConfigureCustom(context, configuration);
|
ConfigureCustom(context, configuration);
|
||||||
ConfigureHealthChecks(context, configuration);
|
ConfigureHealthChecks(context, configuration);
|
||||||
Configure<AbpClockOptions>(options => { options.Kind = DateTimeKind.Local; });
|
Configure<AbpClockOptions>(options => { options.Kind = DateTimeKind.Local; });
|
||||||
|
|
||||||
|
Configure<ServerApplicationOptions>(options =>
|
||||||
|
{
|
||||||
|
configuration.GetSection(nameof(ServerApplicationOptions)).Bind(options);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -79,9 +79,7 @@
|
|||||||
"SaslUserName": "lixiao",
|
"SaslUserName": "lixiao",
|
||||||
"SaslPassword": "lixiao1980",
|
"SaslPassword": "lixiao1980",
|
||||||
"KafkaReplicationFactor": 3,
|
"KafkaReplicationFactor": 3,
|
||||||
"NumPartitions": 30,
|
"NumPartitions": 30
|
||||||
"ServerTagName": "JiSheCollectBus100",
|
|
||||||
"FirstCollectionTime": "2025-04-22 16:07:00"
|
|
||||||
},
|
},
|
||||||
"IoTDBOptions": {
|
"IoTDBOptions": {
|
||||||
"UserName": "root",
|
"UserName": "root",
|
||||||
@ -141,5 +139,10 @@
|
|||||||
"DefaultIdempotence": true
|
"DefaultIdempotence": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"PlugInFolder": ""
|
"PlugInFolder": "",
|
||||||
|
"ServerApplicationOptions": {
|
||||||
|
"ServerTagName": "JiSheCollectBus100",
|
||||||
|
"FirstCollectionTime": "2025-04-22 16:07:00",
|
||||||
|
"AutomaticVerificationTime": "16:07:00"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user