合并代码

This commit is contained in:
ChenYi 2025-04-25 08:33:13 +08:00
commit f2be3a5516
22 changed files with 614 additions and 236 deletions

View File

@ -1,11 +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.Consts;
using JiShe.CollectBus.Common.Extensions; using JiShe.CollectBus.Common.Extensions;
using JiShe.CollectBus.Common.Models;
using JiShe.CollectBus.FreeRedis; 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;
@ -13,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;
@ -28,7 +32,7 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts
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>(); _redisProvider = serviceProvider.GetRequiredService<IFreeRedisProvider>();
} }
@ -51,7 +55,7 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts
await _redisProvider.Instance.HSetAsync($"{RedisConst.ProtocolKey}", Info.Name, Info); 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>
@ -86,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)
@ -384,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
} }
} }

View File

@ -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);

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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

View File

@ -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>
/// 抄读功能码 /// 抄读功能码
@ -24,7 +18,7 @@ namespace JiShe.CollectBus.Common.BuildSendDatas
/// <summary> /// <summary>
/// 抄读计量点,也就是终端电表对应端口 /// 抄读计量点,也就是终端电表对应端口
/// </summary> /// </summary>
public int Pn { get; set; } public int Pn { get; set; }
/// <summary> /// <summary>
/// 透明转发单元 /// 透明转发单元

View File

@ -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; }
}
}

View File

@ -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;
@ -26,5 +27,10 @@ namespace JiShe.CollectBus.Protocol.Test
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override Task<ProtocolBuildResponse> BuildAsync(ProtocolBuildRequest request)
{
throw new NotImplementedException();
}
} }
} }

View File

@ -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
}
}

View File

@ -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; }
}
}

View File

@ -0,0 +1,13 @@
namespace JiShe.CollectBus.Protocol.SendData
{
/// <summary>
/// 返回645报文结果
/// </summary>
public class Telemetry645PacketResponse
{
/// <summary>
/// 报文体
/// </summary>
public List<string> Data { get; set; }
}
}

View File

@ -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");
@ -73,7 +78,7 @@ namespace JiShe.CollectBus.Protocol
await HeartbeatAsync(client, messageReceived, tB3761.A.Code, tB3761.A.A3?.D1_D7, tB3761.SEQ?.PSEQ); await HeartbeatAsync(client, messageReceived, tB3761.A.Code, tB3761.A.A3?.D1_D7, tB3761.SEQ?.PSEQ);
} }
} }
} }
} }
@ -89,7 +94,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);
@ -136,7 +141,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.,
@ -149,11 +154,12 @@ namespace JiShe.CollectBus.Protocol
Fn = 1 Fn = 1
}; };
var bytes = Build3761SendData.BuildSendCommandBytes(reqParam); var bytes = Build3761SendData.BuildSendCommandBytes(reqParam);
var issuedEventMessage = new IssuedEventMessage var issuedEventMessage = new IssuedEventMessage
{ {
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
}; };
//await _producerBus.PublishAsync(ProtocolConst.SubscriberLoginIssuedEventName, new IssuedEventMessage { ClientId = messageReceived.ClientId, DeviceNo = messageReceived.DeviceNo, Message = bytes, Type = IssuedEventType.Login, MessageId = messageReceived.MessageId }); //await _producerBus.PublishAsync(ProtocolConst.SubscriberLoginIssuedEventName, new IssuedEventMessage { ClientId = messageReceived.ClientId, DeviceNo = messageReceived.DeviceNo, Message = bytes, Type = IssuedEventType.Login, MessageId = messageReceived.MessageId });
@ -175,7 +181,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;
@ -252,11 +258,76 @@ 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

View File

@ -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;

View File

@ -7,6 +7,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,6 +20,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.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -27,6 +30,7 @@ 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
{ {
@ -41,8 +45,8 @@ namespace JiShe.CollectBus.ScheduledMeterReading
private readonly IRedisDataCacheService _redisDataCacheService; private readonly IRedisDataCacheService _redisDataCacheService;
private readonly KafkaOptionConfig _kafkaOptions; private readonly KafkaOptionConfig _kafkaOptions;
private readonly IoTDBRuntimeContext _runtimeContext; private readonly IoTDBRuntimeContext _runtimeContext;
private readonly IServiceProvider _serviceProvider; private readonly IProtocolService _protocolService;
int pageSize = 3000; int pageSize = 3000;
public BasicScheduledMeterReadingService( public BasicScheduledMeterReadingService(
@ -51,7 +55,7 @@ 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)
{ {
_logger = logger; _logger = logger;
@ -60,7 +64,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
_producerService = producerService; _producerService = producerService;
_redisDataCacheService = redisDataCacheService; _redisDataCacheService = redisDataCacheService;
_kafkaOptions = kafkaOptions.Value; _kafkaOptions = kafkaOptions.Value;
_serviceProvider = serviceProvider; _protocolService = protocolService;
_runtimeContext.UseTableSessionPool = true; _runtimeContext.UseTableSessionPool = true;
} }
@ -145,15 +149,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 +167,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
@ -500,11 +504,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 +614,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 +633,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 +645,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,
@ -851,10 +839,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 +899,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 +920,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 +982,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 +1109,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++;

View File

@ -16,6 +16,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,7 +40,7 @@ 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,
@ -46,20 +48,20 @@ namespace JiShe.CollectBus.ScheduledMeterReading
IOptions<KafkaOptionConfig> kafkaOptions, IOptions<KafkaOptionConfig> kafkaOptions,
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)
{ {
serverTagName = kafkaOptions.Value.ServerTagName; serverTagName = kafkaOptions.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;
@ -178,14 +180,13 @@ namespace JiShe.CollectBus.ScheduledMeterReading
/// </summary> /// </summary>
/// <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,61 +227,53 @@ 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
{ {
_logger.LogError($"集中器[{settingInfo.FocusAddress}],[{settingInfo.MeterId}]阀控命令错误:{settingInfo.TripType},-102"); _logger.LogError($"集中器[{settingInfo.FocusAddress}],[{settingInfo.MeterId}]阀控命令错误:{settingInfo.TripType},-102");
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 string taskMark = CommonHelper.GetTaskMark(builderResponse.AFn, builderResponse.Fn, ammeterInfo.MeteringCode, builderResponse.MSA,builderResponse.Seq);
{
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{temCode}无效编码,-103");
continue;
}
if (builderResponse == null)
{
_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 +285,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 +303,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 +327,6 @@ namespace JiShe.CollectBus.ScheduledMeterReading
throw; throw;
} }
throw new NotImplementedException($"{nameof(GetAmmeterInfoList)}请根据不同系统类型进行实现");
} }
/// <summary> /// <summary>

View File

@ -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);
} }

View File

@ -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

View File

@ -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;

View File

@ -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; }
}
}

View File

@ -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
}
}

View File

@ -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;
} }