From 8250cf1e0c4e8fc2aec67cb5733caa12310d79f4 Mon Sep 17 00:00:00 2001 From: Dai Mr <1822802785@qq.com> Date: Fri, 27 Dec 2024 17:00:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=84=E8=AF=BB=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EnergySystem/Dto/AddFocusLogInput.cs | 42 + .../Dto/AddSignalStrengthInput.cs | 36 + .../Dto/AmmeterArchivesDownInput.cs | 2 +- .../EnergySystem/Dto/ReadingInput.cs | 2 +- .../EnergySystem/Dto/TimeSetInput.cs | 8 +- .../EnergySystem/IEnergySystemAppService.cs | 21 + .../EnergySystem/EnergySystemAppService.cs | 493 ++++++++++- src/JiShe.CollectBus.Common/Enums/376Enums.cs | 54 +- .../Extensions/HexStringExtensions.cs | 804 ++++++++++++++++-- .../Extensions/StringExtensions.cs | 29 +- .../Models/ReqParameter.cs | 25 +- .../Abstracts/BaseProtocolPlugin.cs | 19 + 12 files changed, 1453 insertions(+), 82 deletions(-) create mode 100644 src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AddFocusLogInput.cs create mode 100644 src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AddSignalStrengthInput.cs diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AddFocusLogInput.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AddFocusLogInput.cs new file mode 100644 index 0000000..094fca2 --- /dev/null +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AddFocusLogInput.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JiShe.CollectBus.EnergySystem.Dto +{ + /// + /// 集中器上下线、心跳记录 + /// + public class AddFocusLogInput + { + /// + /// 集中器编号 + /// + public string Address { get; set; } + + /// + /// 采集主站 + /// + public string GatherServerId { get; set; } + + /// + /// 间隔时间 (DateTime.Now.Minute - LogTime.Minute) + /// + public string IntervalTime { get; set; } + + /// + /// 离/在线发生时间 + /// + public DateTime LogTime { get; set; } + + /// + /// HeartBeat 终端心跳;SignIn 终端登录;SignOut 终端登出 + /// + public string LogType { get; set; } + + + public string Remark { get; set; } + } +} diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AddSignalStrengthInput.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AddSignalStrengthInput.cs new file mode 100644 index 0000000..feda6f1 --- /dev/null +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AddSignalStrengthInput.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JiShe.CollectBus.EnergySystem.Dto +{ + /// + /// 记录信号强度 + /// + public class AddSignalStrengthInput + { + /// + /// 区域编号 + /// + public string AreaCode { get; set; } + + /// + /// 区域地址 + /// + public string Address { get; set; } + + /// + /// 1电表 2水表 3集中器 + /// + public int DeviceType { get; set; } + + /// + /// 信号强度 + /// + public string Csq { get; set; } + + + } +} diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AmmeterArchivesDownInput.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AmmeterArchivesDownInput.cs index 78be984..a561252 100644 --- a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AmmeterArchivesDownInput.cs +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AmmeterArchivesDownInput.cs @@ -91,7 +91,7 @@ namespace JiShe.CollectBus.EnergySystem.Dto public int DecimalCount { get; set; } /// - /// 集中器地址 + /// 采集器地址 /// public string GatherAddress { get; set; } diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/ReadingInput.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/ReadingInput.cs index 07c9c42..0f09c66 100644 --- a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/ReadingInput.cs +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/ReadingInput.cs @@ -14,7 +14,7 @@ namespace JiShe.CollectBus.EnergySystem.Dto /// /// 电表ID /// - public string AmmeterId { get; set; } + public int AmmeterId { get; set; } /// ///采集编码 {"0C_129", "0C_131"}, 采集编码.0C_129:正向有功;C_131:反向有功 diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/TimeSetInput.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/TimeSetInput.cs index 56da498..ee4ead5 100644 --- a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/TimeSetInput.cs +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/TimeSetInput.cs @@ -41,18 +41,18 @@ namespace JiShe.CollectBus.EnergySystem.Dto /// public string Month { get; set; } - public List Data { get; set; } + public List Data { get; set; } } - public class TimeSetDataDataInput + public class TimeSetMutileRateDetailInput { public string Rate { get; set; } - public List Times { get; set; } + public List Times { get; set; } } - public class TimeSetDataDataTimeInput + public class TimeSetTimesInput { public string StartTime { get; set; } diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/IEnergySystemAppService.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/IEnergySystemAppService.cs index c9f737e..4c56fb9 100644 --- a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/IEnergySystemAppService.cs +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/IEnergySystemAppService.cs @@ -124,4 +124,25 @@ public interface IEnergySystemAppService : IApplicationService /// /// Task AdjustMeterTiming(AdjustMeterTimingInput input); + + /// + /// 更新集中器在线记录 + /// + /// + /// + Task AddConrOnlineRecord(AddConrOnlineRecordInput input); + + /// + /// 记录信号强度 + /// + /// + /// + Task AddSignalStrength(AddSignalStrengthInput input); + + /// + /// 集中器上下线、心跳记录 + /// + /// + /// + Task AddFocusLog(AddFocusLogInput input); } \ No newline at end of file diff --git a/src/JiShe.CollectBus.Application/EnergySystem/EnergySystemAppService.cs b/src/JiShe.CollectBus.Application/EnergySystem/EnergySystemAppService.cs index cd68a1a..4a4c6ce 100644 --- a/src/JiShe.CollectBus.Application/EnergySystem/EnergySystemAppService.cs +++ b/src/JiShe.CollectBus.Application/EnergySystem/EnergySystemAppService.cs @@ -1,95 +1,542 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; using System.Threading.Tasks; +using DotNetCore.CAP; +using JiShe.CollectBus.Common.Enums; +using JiShe.CollectBus.Common.Extensions; +using JiShe.CollectBus.Common.Models; using JiShe.CollectBus.EnergySystem.Dto; +using JiShe.CollectBus.FreeSql; +using JiShe.CollectBus.PrepayModel; +using JiShe.CollectBus.Protocol.Contracts; +using MassTransit; +using Newtonsoft.Json; namespace JiShe.CollectBus.EnergySystem { public class EnergySystemAppService: CollectBusAppService,IEnergySystemAppService { - public Task> ValveControl(ValveControlInput input) + private readonly ICapPublisher _capBus; + + public EnergySystemAppService(ICapPublisher capBus) { - throw new NotImplementedException(); + _capBus = capBus; } - public Task> ReadTime(ReadTimeInput input) + /// + /// 电表、水表阀控 透明转发 + /// + /// + /// + public async Task> ValveControl(ValveControlInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + + byte[] bytes = null; + var state = input.TripState == 0 ? true : false; + var address = $"{input.AreaCode}{input.Address}"; + if (input.MeterType == 1) + { + var ammeter = await SqlProvider.Instance.Change(DbEnum.EnergyDB).Select().Where(d => d.ID == input.AmmeterId).FirstAsync(); + if (ammeter == null) return result; + + var dataUnit = + HexStringExtensions.BuildAmmeterValveControlSendDataUnit(ammeter.Address, "", ammeter.Password, + state); + bytes = HexStringExtensions.BuildTransparentForwardingSendCmd(address, ammeter.PortNumber ?? 2, ammeter.BaudRate, dataUnit); + } + else if(input.MeterType == 2) + { + //TODO:水表阀控 + } + + if (bytes == null) + return result; + + + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + result.Status = true; + result.Msg = "操作成功"; + result.Data.ValidData = true; + return result; } - public Task> AmmeterArchivesDown(AmmeterArchivesDownInput input) + /// + /// 批量抄读时段 透明转发 + /// + /// + /// + /// + public async Task> ReadTime(ReadTimeInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto + { + Data = new ReadTimeOutput() + }; + + var ammeter = await SqlProvider.Instance.Change(DbEnum.EnergyDB).Select().Where(d => d.ID == input.AmmeterId).FirstAsync(); + if (ammeter == null) return result; + + var address = $"{input.AreaCode}{input.Address}"; + var bytesList = HexStringExtensions.BuildReadMeterTimeSetSendCmd(address, ammeter.Code, ammeter.Address, ammeter.Password, + ammeter.PortNumber ?? 2, ammeter.BaudRate); + + foreach (var bytes in bytesList) + { + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + } + + return result; } + /// + /// 档案下发 AFN:04 FN:10 + /// + /// + /// + public async Task> AmmeterArchivesDown(AmmeterArchivesDownInput input) + { + var result = new BaseResultDto(); + var address = $"{input.AreaCode}{input.Address}"; + var meterParameters = input.Details.Data.Select(it => new AmmeterParameter() + { + SerialNumber = it.SerialNumber, + Pn = it.Pn, + BaudRate = HexStringExtensions.GetBaudreate(it.Rate.ToString()), + Port = it.Port, + ProtocolType = HexStringExtensions.GetProtocolType(it.AgreementType), + Address = it.Addrress, + Password = it.Password.ToString(), + RateNumber = it.RatesCount, + IntegerBitNumber = it.IntegerCount, + DecimalBitNumber = it.DecimalCount, + CollectorAddress = it.GatherAddress, + //UserCategoryNumber = it.UserBigNumber, + //UserSubclassNumber = it.UserSmallNumber + + }).ToList(); + var bytes = HexStringExtensions.BuildAmmeterParameterSetSendCmd(address, meterParameters); + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + result.Status = true; + result.Msg = "操作成功"; + result.Data.ValidData = true; + return result; + } + + /// + /// 一键匹配 透明转发 + /// + /// + /// + /// public Task AmmeterArchivesMatch(AmmeterArchivesMatchInput input) { throw new NotImplementedException(); } - public Task CommunicationParametersSet(CommunicationParametersSetInput input) + /// + /// 通讯参数设置 AFN:04 FN:3 + /// + /// + /// + /// + public async Task CommunicationParametersSet(CommunicationParametersSetInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + var address = $"{input.AreaCode}{input.Address}"; + var masterIPAndPortArr = input.Data.MasterIPandPort.Split(':'); + var masterIP = masterIPAndPortArr[0]; + var materPort = masterIPAndPortArr[1]; + if (!masterIP.IsValidIPv4() || !materPort.IsValidPort()) + { + result.Status = false; + result.Msg = "主站IP和端口格式错误"; + return result; + } + var backupIPAndPortArr = input.Data.BackupIPandPort.Split(':'); + var backupIP = backupIPAndPortArr[0]; + var backupPort = backupIPAndPortArr[1]; + if (!backupIP.IsValidIPv4() || !backupPort.IsValidPort()) + { + result.Status = false; + result.Msg = "主站IP和端口格式错误"; + return result; + } + + var bytes = HexStringExtensions.BuildCommunicationParametersSetSendCmd(address, masterIP, materPort, + backupIP, backupPort, input.Data.APN); + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + + result.Status = true; + result.Msg = "操作成功"; + return result; } - public Task CallTimeTesting(CallTimeTestingInput input) + /// + /// 召测时间 AFN:0C FN:2 + /// + /// + /// + /// + public async Task CallTimeTesting(CallTimeTestingInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + var address = $"{input.AreaCode}{input.Address}"; + + var bytes = HexStringExtensions.BuildTerminalCalendarClockSendCmd(address); + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + + result.Status = true; + result.Msg = "操作成功"; + return result; } - public Task TimeAdjust(TimeAdjustInput input) + /// + /// 时间校准 AFN:05 FN:31 + /// + /// + /// + /// + public async Task TimeAdjust(TimeAdjustInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + var address = $"{input.AreaCode}{input.Address}"; + + var bytes = HexStringExtensions.BuildConrCheckTimeSendCmd(address,DateTime.Now); + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + + result.Status = true; + result.Msg = "操作成功"; + return result; } - public Task TerminalRestart(TerminalRestartInput input) + /// + /// 重启终端 AFN:01 FN:1 + /// + /// + /// + /// + public async Task TerminalRestart(TerminalRestartInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + var address = $"{input.AreaCode}{input.Address}"; + + var bytes = HexStringExtensions.BuildConrRebootSendCmd(address); + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + + result.Status = true; + result.Msg = "操作成功"; + return result; } - public Task> ReadMeterNum(ReadMeterNumInput input) + /// + /// 读取表号 AFN:0A FN:10 + /// + /// + /// + /// + public async Task> ReadMeterNum(ReadMeterNumInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + + var address = $"{input.AreaCode}{input.Address}"; + var pnList = input.Data.Split(',').Select(it => int.Parse(it)).ToList(); + var bytes = HexStringExtensions.BuildAmmeterParameterReadingSendCmd(address, pnList); + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + result.Status = true; + result.Msg = "操作成功"; + return result; } - public Task> Reading(ReadingInput input) + /// + /// 随抄 + /// + /// + /// + /// + public async Task> Reading(ReadingInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + var ammeter = await SqlProvider.Instance.Change(DbEnum.EnergyDB).Select().Where(d => d.ID == input.AmmeterId).FirstAsync(); + if (ammeter == null || !ammeter.MeterCode.HasValue) return result; + + var bytesList = new List(); + var address = $"{input.AreaCode}{input.Address}"; + var itemCodeList = JsonConvert.DeserializeObject>(input.ItemCodes); + foreach (var itemCode in itemCodeList) + { + var itemCodeArr = itemCode.Split('_'); + var aFN = (AFN)itemCodeArr[0].HexToDec(); + var fn = int.Parse(itemCodeArr[1]); + if (aFN == AFN.请求实时数据) + { + var bytes = HexStringExtensions.BuildAmmeterReadRealTimeDataSendCmd(address, ammeter.MeterCode.Value, (ATypeOfDataItems)fn); + bytesList.Add(bytes); + } + else if (aFN == AFN.请求历史数据) + { + var density = (FreezeDensity)input.Density; + var bytes = HexStringExtensions.BuildAmmeterReadingIIdataTypeItemsSendCmd(address, ammeter.MeterCode.Value, (IIdataTypeItems)fn, density,0); + bytesList.Add(bytes); + } + } + + foreach (var bytes in bytesList) + { + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + + } + result.Status = true; + result.Msg = "操作成功"; + return result; } - public Task TimeSet(TimeSetInput input) + /// + /// 设置时间段 透明转发 + /// + /// + /// + /// + public async Task TimeSet(TimeSetInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + + var ammeter = await SqlProvider.Instance.Change(DbEnum.EnergyDB).Select().Where(d => d.ID == input.MeterID).FirstAsync(); + if (ammeter == null) return result; + + var address = input.FocusCode; + var timeDataList = input.Data.Select(it => new TimeSetDetail() + { + Months = it.Month.Split(',').Select(m => int.Parse(m)).ToArray(), + Data = it.Data.Select(d => new MutileRateDetail() + { + Rate = d.Rate, + Times = d.Times.Select(t => new Times() + { + StartTime = t.StartTime, + EndTime = t.EndTime + }).ToList() + }).ToList() + }).ToList(); + var bytesList = HexStringExtensions.BuildAmmeterSetTimeSetSendCmd(address, ammeter.Code, ammeter.Address, + ammeter.PortNumber ?? 2, ammeter.BaudRate, timeDataList); + + foreach (var bytes in bytesList) + { + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + } + result.Status = true; + result.Msg = "操作成功"; + return result; } + /// + /// 设置自动上报采集项 数据库操作 + /// + /// + /// + /// public Task AutoReportCollectionItemsSet(AutoReportCollectionItemsSetInput input) { throw new NotImplementedException(); } + /// + /// 设置自动上报 数据库操作 + /// + /// + /// + /// public Task AutoReportSet(AutoReportSetInput input) { throw new NotImplementedException(); } + /// + /// 查询自动上报开启状态 数据库操作 + /// + /// + /// + /// public Task QueryAutoReportOpenStatus(QueryAutoReportOpenStatusInput input) { throw new NotImplementedException(); } - public Task> BatchReadVersion(BatchReadVersionInput input) + /// + /// 批量抄读版本号 AFN:09 FN:1 + /// + /// + /// + /// + public async Task> BatchReadVersion(BatchReadVersionInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + foreach (var data in input.Data) + { + var address = $"{data.AreaCode}{data.Address}"; + var bytes = HexStringExtensions.BuildTerminalVersionInfoReadingSendCmd(address); + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + } + result.Status = true; + result.Msg = "操作成功"; + return result; } + /// + /// 查询采集日志 数据库 + /// + /// + /// + /// public Task> QueryRecordLog(QueryRecordLogInput input) { throw new NotImplementedException(); } - public Task AdjustMeterTiming(AdjustMeterTimingInput input) + /// + /// 校准电表时间 透明转发 + /// + /// + /// + /// + public async Task AdjustMeterTiming(AdjustMeterTimingInput input) + { + var result = new BaseResultDto(); + + var ammeter = await SqlProvider.Instance.Change(DbEnum.EnergyDB).Select().Where(d => d.Address == input.MeterAddress).FirstAsync(); + if (ammeter == null) return result; + + var address = $"{input.AreaCode}{input.Address}"; + var bytesList = HexStringExtensions.BuildAmmeterCorrectionTimeSendCmd(address, ammeter.Code, ammeter.Address, ammeter.Password, + ammeter.PortNumber ?? 2, ammeter.BaudRate); + + foreach (var bytes in bytesList) + { + await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage + { + //ClientId = messageReceived.ClientId, + DeviceNo = address, + Message = bytes, + Type = IssuedEventType.Data, + MessageId = NewId.NextGuid().ToString() + }); + } + + result.Status = true; + result.Msg = "操作成功"; + return result; + } + + /// + /// 更新集中器在线记录 数据库 + /// + /// + /// + /// + public Task AddConrOnlineRecord(AddConrOnlineRecordInput input) + { + throw new NotImplementedException(); + } + + /// + /// 记录信号强度 数据库 + /// + /// + /// + /// + public Task AddSignalStrength(AddSignalStrengthInput input) + { + throw new NotImplementedException(); + } + + /// + /// 集中器上下线、心跳记录 数据库 + /// + /// + /// + /// + public Task AddFocusLog(AddFocusLogInput input) { throw new NotImplementedException(); } diff --git a/src/JiShe.CollectBus.Common/Enums/376Enums.cs b/src/JiShe.CollectBus.Common/Enums/376Enums.cs index 661c250..a64aa54 100644 --- a/src/JiShe.CollectBus.Common/Enums/376Enums.cs +++ b/src/JiShe.CollectBus.Common/Enums/376Enums.cs @@ -1,5 +1,4 @@ using System.ComponentModel; -using System.Reflection.Metadata; namespace JiShe.CollectBus.Common.Enums { @@ -190,7 +189,8 @@ namespace JiShe.CollectBus.Common.Enums { 相位角=49, 当前正向有功电能示值=129, - 上月最大需量=149, + 当前反向无功电能示值 = 131, + 上月最大需量 =149, } /// @@ -315,4 +315,54 @@ namespace JiShe.CollectBus.Common.Enums [Description("月冻结类")] Td_m, } + + public enum CmdType + { + Valve = 1, + Lock, + Reading, + BalanceDown, + BalanceRead, + PowerDown, + PowerRead, + ArchivesDown, + ArchivesRead, + Clear, + TimeSet, + Identity, + ReadMeterNum, + Event, + + /// + /// 抄读电流 + /// + ReadingCurrent, + CurrentDown, + CurrentRead, + + /// + /// 威胜的功率下发(海洋职业学院专用) + /// + WsPowerDown, + WsOnPowerDown, + ReadMeterStatus, + ReadTimeSetMonth, + ReadTimeSet, + ReadTimeSetNum, + + /// + /// 读取正在运行的时段 + /// + ReadCurrentTime + } + + public enum TerminalVersionInfoEnum + { + MakerNo = 0, + DeviceNo = 4, + SoftwareVersionNo =12, + SoftwareReleaseDate=16, + HardwareVersionNo = 30 + } + } diff --git a/src/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs b/src/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs index 4af9d45..8d034fa 100644 --- a/src/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs +++ b/src/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs @@ -2,6 +2,10 @@ using JiShe.CollectBus.Common.Enums; using JiShe.CollectBus.Common.Models; using System.Reflection; +using System.Net; +using System.Collections.Generic; +using System.Globalization; +using static System.Runtime.InteropServices.JavaScript.JSType; namespace JiShe.CollectBus.Common.Extensions { @@ -172,7 +176,7 @@ namespace JiShe.CollectBus.Common.Extensions /// /// 集中器地址 /// 对象序号 - public static void BuildAmmeterParameterReadingSendCmd(string address, List meterNumberList) + public static byte[] BuildAmmeterParameterReadingSendCmd(string address, List meterNumberList) { var dataUnit = new List(); var countHex = meterNumberList.Count().DecToHex().PadLeft(4, '0'); @@ -205,6 +209,7 @@ namespace JiShe.CollectBus.Common.Extensions Fn = 10 }; var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; } /// @@ -213,7 +218,7 @@ namespace JiShe.CollectBus.Common.Extensions /// /// /// 一类数据项 - public static void BuildAmmeterReadRealTimeDataSendCmd(string address, int pn, ATypeOfDataItems aTypeOfDataItems) + public static byte[] BuildAmmeterReadRealTimeDataSendCmd(string address, int pn, ATypeOfDataItems aTypeOfDataItems) { var reqParameter = new ReqParameter2() { @@ -232,6 +237,7 @@ namespace JiShe.CollectBus.Common.Extensions Fn = (int)aTypeOfDataItems }; var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter); + return bytes; } /// @@ -298,9 +304,10 @@ namespace JiShe.CollectBus.Common.Extensions /// fn /// 冻结密度 /// 冻结点数 - public static void BuildAmmeterReadingIIdataTypeItemsSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, FreezeDensity density,int points) + /// 起始时间 + public static byte[] BuildAmmeterReadingIIdataTypeItemsSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, FreezeDensity density,int points,DateTime? beginTime = null) { - var queryDate = DateTime.Today.AddDays(-1); + var queryDate = beginTime ?? DateTime.Today.AddDays(-1); var dataUnit = queryDate.ToString("yyMMddHHmm").StringToPairs(); dataUnit.Reverse(); @@ -326,6 +333,7 @@ namespace JiShe.CollectBus.Common.Extensions Fn = (int)iIDataTypeItems }; var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; } /// @@ -335,9 +343,10 @@ namespace JiShe.CollectBus.Common.Extensions /// /// fn /// 数据时标 - public static void BuildAmmeterReadingBaseDataSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems,TdType tdType) + /// 起始时间 + public static void BuildAmmeterReadingBaseDataSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems,TdType tdType, DateTime? beginTime = null) { - var queryDate = DateTime.Today.AddDays(-1); + var queryDate = beginTime ?? DateTime.Today.AddDays(-1); List? dataUnit = null; switch (tdType) { @@ -408,7 +417,7 @@ namespace JiShe.CollectBus.Common.Extensions /// /// /// - public static void BuildAmmeterSuperpowerSettingSendCmd(string address, string password,string modelCode, int port, BaudRate baudRate, decimal power) + public static void BuildAmmeterSuperpowerSettingSendCmd(string address, string password,string modelCode, int port, string baudRate, decimal power) { if (power > 0) { @@ -454,7 +463,7 @@ namespace JiShe.CollectBus.Common.Extensions /// /// /// - public static void BuildAmmeterAbsolutePowerSettingSendCmd(string address, string password, int port, BaudRate baudRate, decimal power) + public static void BuildAmmeterAbsolutePowerSettingSendCmd(string address, string password, int port, string baudRate, decimal power) { if (power <= 0) { @@ -494,7 +503,7 @@ namespace JiShe.CollectBus.Common.Extensions /// /// /// - public static void BuildAmmeterPowerFactorSettingSendCmd(string address, string password, int port, BaudRate baudRate, decimal power) + public static void BuildAmmeterPowerFactorSettingSendCmd(string address, string password, int port, string baudRate, decimal power) { string dataMark; //如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001 @@ -529,7 +538,7 @@ namespace JiShe.CollectBus.Common.Extensions /// /// /// - public static void WsOnSupperPower(string address,string password,string modelCode,bool isOn,int port,BaudRate baudRate) + public static void WsOnSupperPower(string address,string password,string modelCode,bool isOn,int port,string baudRate) { List modelCodes = new List() { "DDS3102-S2", "DDS71", "DDZY71", "DTZY71", "DSZY71" }; @@ -574,22 +583,194 @@ namespace JiShe.CollectBus.Common.Extensions return bytes; } + + /// + /// 构建通讯参数设置-下发命令 + /// + /// 集中器地址 + /// 主站ip + /// 主站端口 + /// 备用ip和端口 + /// 备用ip和端口 + /// APN:CMNET 63 6D 6E 65 74 + /// + public static byte[] BuildCommunicationParametersSetSendCmd(string address,string masterIP,string masterPort, + string backupIP,string backupPort, string aPN) + { + var dataUnit = new List(); + var masterIPList = masterIP.Split('.').Select(it => int.Parse(it).DecToHex().PadLeft(2,'0')).ToList(); + dataUnit.AddRange(masterIPList); + + var masterPortList = int.Parse(masterPort).DecToHex().PadLeft(4, '0').StringToPairs(); + masterPortList.Reverse(); + dataUnit.AddRange(masterPortList); + + var backupIPList = backupIP.Split('.').Select(it => int.Parse(it).DecToHex().PadLeft(2, '0')).ToList(); + dataUnit.AddRange(backupIPList); + + var backupPortList = int.Parse(backupPort).DecToHex().PadLeft(4, '0').StringToPairs(); + backupPortList.Reverse(); + dataUnit.AddRange(backupPortList); + + var aPNList = aPN.ToCharArray().Select(it => Convert.ToInt32(it).DecToHex().PadLeft(2, '0')).ToList(); + aPNList.AddRange(Enumerable.Repeat("00",16 - aPNList.Count)); + dataUnit.AddRange(aPNList); + + var reqParameter = new ReqParameter2() + { + AFN = AFN.设置参数, + FunCode = (int)CMasterStationFunCode.请求1级数据, + A = address, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.需要对该帧进行确认, + PRSEQ = 10, + }, + MSA = GetMSA(address), + Pn = 0, + Fn = 3 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; + } + + /// + /// 构建抄读终端日历时钟-下发命令 + /// + /// + public static byte[] BuildTerminalCalendarClockSendCmd(string address) + { + var reqParameter = new ReqParameter2() + { + AFN = AFN.请求实时数据, + FunCode = (int)CMasterStationFunCode.请求2级数据, + A = address, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.不需要对该帧进行确认, + PRSEQ = 2, + }, + MSA = GetMSA(address), + Pn = 0, + Fn = 2 + }; + var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter); + return bytes; + } + + /// + /// 构建终端版本信息读取-下发命令 + /// + /// + public static byte[] BuildTerminalVersionInfoReadingSendCmd(string address) + { + var reqParameter = new ReqParameter2() + { + AFN = AFN.请求终端配置, + FunCode = (int)CMasterStationFunCode.请求2级数据, + A = address, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.不需要对该帧进行确认, + PRSEQ = 2, + }, + MSA = GetMSA(address), + Pn = 0, + Fn = 1 + }; + var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter); + return bytes; + } + + /// + /// 集中器校时 秒、分、时、日、星期-月(3-1+4)、年 + /// + /// + /// + /// + public static byte[] BuildConrCheckTimeSendCmd(string address, DateTime time) + { + var week = ((int)time.DayOfWeek).DecToBin().PadLeft(3, '0'); + var monthTemp = time.Month.ToString().PadLeft(2, '0'); + var m1 = int.Parse(monthTemp[0].ToString()).DecToBin();//十位 + var m2 = int.Parse(monthTemp[1].ToString()).DecToBin().PadLeft(4, '0');//个位 + var weekAndMonthHex = (week + m1 + m2).BinToHex().ToUpper(); + + var strTimeFm = time.ToString("ss mm HH dd $$ yy").Replace("$$", weekAndMonthHex); + var dataUnit = strTimeFm.Replace(" ", "").StringToPairs(); + dataUnit.AddRange(GetPW()); + var reqParameter = new ReqParameter2() + { + AFN = AFN.控制命令, + FunCode = (int)CMasterStationFunCode.请求1级数据, + A = address, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.需要对该帧进行确认, + PRSEQ = 10, + }, + MSA = GetMSA(address), + Pn = 0, + Fn = 31 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; + } + + /// + /// 硬件初始化 + /// + /// + /// + public static byte[] BuildConrRebootSendCmd(string address) + { + var dataUnit = GetPW(); + var reqParameter = new ReqParameter2() + { + AFN = AFN.复位, + FunCode = (int)CMasterStationFunCode.复位命令, + A = address, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.需要对该帧进行确认, + PRSEQ = 10, + }, + MSA = GetMSA(address), + Pn = 0, + Fn = 1 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; + } + /// /// 构建透明转发-下发命令 /// /// 集中器地址 /// 终端通信端口 1~31 - /// 0~7 对应300,600,1200,2400,4800,7200,9600,19200 + /// 300,600,1200,2400,4800,7200,9600,19200对应 0~7 /// 转发内容 /// 停止位 /// 校验方式 /// 数据位 /// 等待报文超时时间/s /// 等待字节超时时间/ms - public static byte[] BuildTransparentForwardingSendCmd(string address, int port, BaudRate baudRate, List datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8, + public static byte[] BuildTransparentForwardingSendCmd(string address, int port, string baudRate, List datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8, int waitContentTimeout = 100, int waitByteTimeout = 100) { - var dataUnit = BuildTransparentForwardingSendDataUnit(port, baudRate, datas, stopBit, parity, dataBit, waitContentTimeout, waitByteTimeout); + var baudRateValue = GetBaudreate(baudRate); + + var dataUnit = BuildTransparentForwardingSendDataUnit(port, baudRateValue, datas, stopBit, parity, dataBit, waitContentTimeout, waitByteTimeout); dataUnit.AddRange(GetPW()); var reqParameter = new ReqParameter2() { @@ -611,6 +792,46 @@ namespace JiShe.CollectBus.Common.Extensions return bytes; } + /// + /// 根据波特率获取值 + /// + /// + /// + public static int GetBaudreate(string val) + { + var type = 0; + switch (val) + { + case "300": type = 0; break; + case "600": type = 1; break; + case "1200": type = 2; break; + case "2400": type = 3; break; + case "4800": type = 4; break; + case "7200": type = 5; break; + case "9600": type = 6; break; + case "19200": type = 7; break; + } + return type; + } + + /// + /// 根据波特率获取值 + /// + /// + /// + public static int GetProtocolType(string val) + { + var type = 0; + switch (val) + { + case "DL/T 645—2007": type = 30; break; + case "DL/T 645—1997": type = 1; break; + case "交流采样装置": type = 2; break; + case "串行接口连接窄带低压载波通讯": type = 31; break; + } + return type; + } + [Obsolete] public static List AmmeterValveControl(string address, string specialnocode, string password, bool state, string modelCode = "") { @@ -675,7 +896,7 @@ namespace JiShe.CollectBus.Common.Extensions /// 等待报文超时时间/s /// 等待字节超时时间/ms /// - private static List BuildTransparentForwardingSendDataUnit(int port, BaudRate baudRate, List datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8, + private static List BuildTransparentForwardingSendDataUnit(int port, int baudRate, List datas, StopBit stopBit = StopBit.Stop1, Parity parity = Parity.Even, DataBit dataBit = DataBit.D8, int waitContentTimeout = 100, int waitByteTimeout = 100) { var dataUnit = new List(); @@ -683,7 +904,7 @@ namespace JiShe.CollectBus.Common.Extensions var portHex = port.DecToHex().PadLeft(2, '0'); dataUnit.Add(portHex); - var baudRateBin = ((int)baudRate).DecToBin().PadLeft(3, '0'); + var baudRateBin = baudRate.DecToBin().PadLeft(3, '0'); var stopBitBin = ((int)stopBit).DecToBin(); var parityBin = parity != Parity.None ? $"1{((int)parity).DecToBin()}" : "00"; var dataBitBin = ((int)dataBit).DecToBin().PadLeft(2, '0'); @@ -740,12 +961,12 @@ namespace JiShe.CollectBus.Common.Extensions var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0'); hexDatas.Add(countHex); - //TODO 优化代码:目标数据入参,返回类型为出参 for (int i = 0; i <= meterParameters.Count - 1; i++) { var meter = meterParameters[i]; - var indexHex = (i + 1).DecToHex().PadLeft(4, '0'); + //var indexHex = (i + 1).DecToHex().PadLeft(4, '0'); + var indexHex = meter.SerialNumber.DecToHex().PadLeft(4, '0'); hexDatas.Add(indexHex); var pnHex = meter.Pn.DecToHex().PadLeft(4, '0'); @@ -775,8 +996,13 @@ namespace JiShe.CollectBus.Common.Extensions hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0')); - var userCategoryNumberBin = meter.UserCategoryNumber.DecToBin().PadLeft(4, '0'); - var userSubclassNumberBin = meter.UserSubclassNumber.DecToBin().PadLeft(4, '0'); + var userCategoryNumber = 0;//meter.UserCategoryNumber + var userSubclassNumber = 0;//meter.UserSubclassNumber + if (meter.ProtocolType == 32) userCategoryNumber = 1; + else if (meter.ProtocolType == 45) { userCategoryNumber = 1; userSubclassNumber = 9; } + + var userCategoryNumberBin = userCategoryNumber.DecToBin().PadLeft(4, '0'); + var userSubclassNumberBin = userSubclassNumber.DecToBin().PadLeft(4, '0'); var userNumberHex = $"{userCategoryNumberBin}{userSubclassNumberBin}".BinToHex().PadLeft(2, '0'); hexDatas.Add(userNumberHex); } @@ -897,6 +1123,7 @@ namespace JiShe.CollectBus.Common.Extensions return datas; } + //AUX=消息认证码字段(PW,16个字节) private static List GetPW() { @@ -1116,13 +1343,13 @@ namespace JiShe.CollectBus.Common.Extensions /// /// 构建电表阀控下发数据单元 /// - /// 电表地址 + /// 电表地址 /// 特殊控制码 /// 密码 /// 是否为开阀 /// 型号码 /// - public static List BuildAmmeterValveControlSendDataUnit(string address, string specialControlCode, string password, bool state, string modelCode = "") + public static List BuildAmmeterValveControlSendDataUnit(string ammeterAddress, string specialControlCode, string password, bool state, string modelCode = "") { var code = string.Empty; @@ -1163,7 +1390,7 @@ namespace JiShe.CollectBus.Common.Extensions var strP = password.StrAddSpan().StrReverseOrder(); var strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + code + " 00 " + strDate; var dataUnit = strSJY.Replace(" ", "").StringToPairs(); - var dataList = Build645SendCommand(address, "1C", dataUnit); + var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit); return dataList; //string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2"); @@ -1176,12 +1403,12 @@ namespace JiShe.CollectBus.Common.Extensions /// /// 构建电表保电下发数据单元 /// - /// 电表地址 + /// 电表地址 /// /// true 保电 false 保电解除 /// 型号码 /// - public static List BuildAmmeterLockSendDataUnit(string address, string password, bool state, string modelCode = "") + public static List BuildAmmeterLockSendDataUnit(string ammeterAddress, string password, bool state, string modelCode = "") { var code = state ? "3A" : "3B"; @@ -1194,18 +1421,18 @@ namespace JiShe.CollectBus.Common.Extensions var strSJY = " 02 " + strP + " 01 00 00 00 " + strDate; var dataUnit = strSJY.Replace(" ", "").StringToPairs(); - var dataList = Build645SendCommand(address, "1C", dataUnit); + var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit); return dataList; } /// /// 构建电表认证下发数据单元 /// - /// 电表地址 + /// 电表地址 /// /// /// - public static List BuildAmmeterIdentitySendDataUnit(string address, string ramDon, string maco) + public static List BuildAmmeterIdentitySendDataUnit(string ammeterAddress, string ramDon, string maco) { var codeList = "070004FF".StringToPairs(); codeList.Reverse(); @@ -1220,25 +1447,451 @@ namespace JiShe.CollectBus.Common.Extensions dataUnit.AddRange(codeList); dataUnit.AddRange(ramDonList); dataUnit.AddRange(macoList); - var dataList = Build645SendCommand(address, "03", dataUnit); + var dataList = Build645SendCommand(ammeterAddress, "03", dataUnit); return dataList; } /// /// 构建电表清零下发数据单元 /// - /// 电表地址 + /// 电表地址 /// /// - public static List BuildAmmterClearSendDataUnit(string address, string password) + public static List BuildAmmeterClearSendDataUnit(string ammeterAddress, string password) { var strP = password.StrAddSpan().StrReverseOrder(); var strSJY = " 02 " + strP + " 01 00 00 00 "; var dataUnit = strSJY.Replace(" ", "").StringToPairs(); - var dataList = Build645SendCommand(address, "1A", dataUnit); + var dataList = Build645SendCommand(ammeterAddress, "1A", dataUnit); return dataList; } + + /// + /// 构建电表读取下发数据单元 + /// + /// 电表地址 + /// 功率读取 余额读取 + /// 数据标识 + /// + public static List BuildAmmeterReadDataUnit(string ammeterAddress, CmdType cmdType, string dataId = "") + { + var dn = ""; + if (string.IsNullOrWhiteSpace(dataId)) + { + if (cmdType == CmdType.PowerRead) dn = "04090B01"; + else if (cmdType == CmdType.BalanceRead) dn = "00900200"; + else if (cmdType == CmdType.CurrentRead) dn = "04090801"; + else if (cmdType == CmdType.WsPowerDown) dn = "0E300103"; + else if (cmdType == CmdType.ReadMeterStatus) dn = "04000503"; + else if (cmdType == CmdType.TimeSet) dn = "04010001";//主用第一套时段数据 + else if (cmdType == CmdType.ReadTimeSetMonth) dn = "04010000";//主用时区数据 + else if (cmdType == CmdType.ReadTimeSetNum) dn = "04000202";//日时段数 + } + else + dn = dataId; + + var dataUnit = dn.StringToPairs(true); + + var dataList = Build645SendCommand(ammeterAddress, "11", dataUnit); + return dataList; + } + + /// + /// 构建电表修正时间下发命令 + /// + /// + /// + /// + /// + /// + /// + /// + public static List BuildAmmeterCorrectionTimeSendCmd(string address,string modelCode,string ammeterAddress,string password,int port,string baudRate) + { + var bytesList = new List(); + if (modelCode == "PMAC9523") + { + var now = DateTime.Now; + var year = (now.Year - 2000).ToString("X2").PadLeft(4, '0'); + var month = now.Month.ToString("X2").PadLeft(4, '0'); + var day = now.Day.ToString("X2").PadLeft(4, '0'); + var hour = now.Hour.ToString("X2").PadLeft(4, '0'); + var minute = now.Minute.ToString("X2").PadLeft(4, '0'); + var second = now.Second.ToString("X2").PadLeft(4, '0'); + var adress = int.Parse(ammeterAddress.Substring(ammeterAddress.Length - 3)).DecToHex().PadLeft(2,'0'); + var fm = new List() { adress, "10", "23", "35", "00", "06", "0C" }; + fm.AddRange($"{second}{minute}{hour}{day}{month}{year}".StringToPairs()); + + var bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray(); + var getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0'));//long.Parse ? + fm.AddRange(getCrc); + + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None); + bytesList.Add(bytes); + } + else if (modelCode == "DTSU193") + { + var now = DateTime.Now; + var year = now.Year.ToString().Substring(2); + var month = now.Month.ToString().PadLeft(2, '0'); + var day = now.Day.ToString().PadLeft(2, '0'); + var week = ((int)now.DayOfWeek).ToString().PadLeft(2, '0'); + var hour = now.Hour.ToString().PadLeft(2, '0'); + var minute = now.Minute.ToString().PadLeft(2, '0'); + var second = now.Second.ToString().PadLeft(2, '0'); + var fm = GenerateCTCommand(ammeterAddress,$"{year}{month}{day}{week}{hour}{minute}{second}"); + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm); + bytesList.Add(bytes); + } + else + { + var now = DateTime.Now; + var year = now.Year.ToString().PadLeft(4, '0'); + var month = now.Month.ToString().PadLeft(2, '0'); + var day = now.Day.ToString().PadLeft(2, '0'); + var week = ((int)now.DayOfWeek).ToString().PadLeft(2, '0'); + var hour = now.Hour.ToString().PadLeft(2, '0'); + var minute = now.Minute.ToString().PadLeft(2, '0'); + var second = now.Second.ToString().PadLeft(2, '0'); + + //组装数据域 + List dataList = new List(); + var dataMarkList = "04000101".StringToPairs(true); + dataList.AddRange(dataMarkList); + dataList.Add("02"); + if (string.IsNullOrEmpty(password)) + password = "000000"; + var passwordList = password.StringToPairs(true); + dataList.AddRange(passwordList); + dataList.AddRange("00000000".StringToPairs(true)); + dataList.AddRange($"{year}{month}{day}{week}".StringToPairs(true)); + + var fm = Build645SendCommand(ammeterAddress, "14", dataList); + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm); + bytesList.Add(bytes); + + dataList = new List(); + dataMarkList = "04000102".StringToPairs(true); + dataList.AddRange(dataMarkList); + dataList.Add("02"); + dataList.AddRange(passwordList); + dataList.AddRange("00000000".StringToPairs(true)); + dataList.AddRange($"{hour}{minute}{second}".StringToPairs(true)); + fm = Build645SendCommand(ammeterAddress, "14", dataList); + bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm); + bytesList.Add(bytes); + + } + return bytesList; + } + + /// + /// 构建电表读取时段设置下发命令 + /// + /// + /// + /// + /// + /// + /// + /// + public static List BuildReadMeterTimeSetSendCmd(string address, string modelCode, string ammeterAddress, string password, int port, string baudRate) + { + if (modelCode == "DTSU193") + { + return null; + } + + if (modelCode == "PMAC9523") + { + //LogHelper.LogStr("ReadMeterTimeSet", $"表编号[{meterInfo.meter_address}]进入PMAC9523时段设置"); + var adress = int.Parse(ammeterAddress.Substring(ammeterAddress.Length - 3)).DecToHex().PadLeft(2, '0'); + var fm = new List() { adress, "03", "55", "F9", "00", "28" }; + var bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray(); + var getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0')); + fm.AddRange(getCrc); + + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None); + return new List(){ bytes }; + } + + var bytes1 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010001")); + + var bytes2 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010002")); + + var bytes3 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010003")); + + var bytes4 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010004")); + + var bytes9 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010005")); + + var bytes5 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020001")); + + var bytes6 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020002")); + + var bytes7 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020003")); + + var bytes8 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020004")); + + var bytes10 = BuildTransparentForwardingSendCmd(address, port, baudRate, + BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020005")); + + + return new List{ bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7, bytes8, bytes9, bytes10 }; + } + + /// + /// 构建电表表号读取下发命令 + /// + /// 电表地址 + /// + /// + public static List BuildAmmeterReadNumSendCmd(string ammeterAddress) + { + var dataUnit = "04000402".StringToPairs(true); + return Build645SendCommand(ammeterAddress, "11", dataUnit); + } + + /// + /// 构建设置时段下发命令 + /// + /// + /// + /// + /// + /// + /// + /// + public static List BuildAmmeterSetTimeSetSendCmd(string address,string ammeterAddress,string modelCode,int port,string baudRate, List data) + { + List bytesList = new List(); + if (modelCode == "DTSU193") + { + return null; + } + else if (modelCode == "PMAC9523") + { + var adress = int.Parse(ammeterAddress.Substring(ammeterAddress.Length - 3)).DecToHex().PadLeft(2,'0'); + //第一步启用复费率编程:寄存器64503,写数据01启动编程 + var fm = new List() { adress, "10", "FB", "F6", "00", "01", "02", "00", "01" }; + var bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray(); + var getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0')); + fm.AddRange(getCrc); + + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None); + bytesList.Add(bytes); + + //第二步写复费率模式:寄存器22002,写数据01固定一套费率 + fm = new List() { adress, "10", "55", "F1", "00", "01", "02", "00", "01" }; + bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray(); + getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0')); + fm.AddRange(getCrc); + bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None); + bytesList.Add(bytes); + + //第三步写时段参数:寄存器22010开始,后续多少个寄存器根据时段内容来。 + var timeSetDetailList = data.FirstOrDefault().Data; + fm = new List() { adress, "10", "55", "F9", "00" }; + //寄存器个数 + var timeNum = timeSetDetailList.Sum(o => o.Times.Count); + fm.Add($"{timeNum * 2 + 1:X2}"); + //数据长度 + fm.Add($"{(timeNum * 2 + 1) * 2:X2}"); + + //时段个数 + fm.Add("00"); + fm.Add($"{timeNum:X2}"); + Dictionary setDic = new Dictionary(); + int rate = 0; + foreach (var item in timeSetDetailList) + { + int.TryParse(item.Rate, out rate); + foreach (var itemItem in item.Times) + { + fm.Add("00"); + fm.Add($"{rate - 1:X2}"); + fm.Add("00"); + fm.Add($"{itemItem.StartTime.TakeTimeToInt():X2}"); + } + } + bts = fm.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray(); + getCrc = GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2,'0')); + fm.AddRange(getCrc); + bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, fm, StopBit.Stop1, Parity.None); + bytesList.Add(bytes); + } + else + { + #region 采用TimeSet方法设置 弃用 + //List fm = null; + //SendInfo sendInfo = null; + //List tempSi = new List(); + ////判断是否需要进入编程模式,获取编程模式指令 + //var pm = ProgramModelConfig.ProgramModels.FirstOrDefault(n => n.BrandName == meterInfo.brand_name + //&& n.Model == meterInfo.model_name); + //if (pm != null) + //{ + // if (pm.IsEnter) + // { + // //编程指令 + // var bccmd= pm.cmdData; + // //替换表地址 + // var addressList= Protocol.QGDW3761.DataTypeConvert.CutStr(meterInfo.meter_address, 2, true); + // var addressstr = string.Join(" ",addressList); + // bccmd = bccmd.Replace("AA AA AA AA AA AA", addressstr); + // fm = bccmd.Split(' ').ToList(); + + // //生成CRC + // var CRC = Protocol.QGDW3761.DataTypeConvert.GetCRC(fm); + // fm.Add(CRC); + // fm.Add("16"); + + // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true); + // sendInfo = new SendInfo + // ( + // confirmResult.msa, + // confirmResult.cmd16, + // MeterType.Ammeter, + // CmdType.ProgramModel, + // null, + // sDto + // ); + // si.Add(sendInfo); + // } + // //年时区数 + // int yearTimeZoneCount = 0; + // //日时段数 + // int dayTimeZoneCount = 0; + // //费率 + // int rate = 0; + // //发送两套时区 + // for (int j = 1; j <= 2; j++) + // { + // //发送时区表数据 + // var timeZoneData = GenerateTimeZone(sDto); + // yearTimeZoneCount = timeZoneData.Count / 3; + // fm = GenerateCTCommand($"040{j}0000", string.Join("", timeZoneData)); + // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true); + // sendInfo = new SendInfo + // ( + // confirmResult.msa, + // confirmResult.cmd16, + // MeterType.Ammeter, + // CmdType.SetTimeSet, + // null, + // sDto + // ); + // tempSi.Add(sendInfo); + // //发送日时段数据 + // for (int i = 1; i <= sDto.data.Count; i++) + // { + // var dayTimeZone = GenerateDayTimeZone(sDto.data[i - 1].data); + + // fm = GenerateCTCommand($"040{j}000{i}", string.Join("", dayTimeZone)); + // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true); + // sendInfo = new SendInfo + // ( + // confirmResult.msa, + // confirmResult.cmd16, + // MeterType.Ammeter, + // CmdType.SetTimeSet, + // null, + // sDto + // ); + // tempSi.Add(sendInfo); + + // //计算日时段数 + // var dz = dayTimeZone.Count / 3; + // if (dz > dayTimeZoneCount) dayTimeZoneCount = dz; + // //计算费率 + + // foreach(var detail in sDto.data[i - 1].data) + // { + // int rt = Convert.ToInt32(detail.rate); + // if (rt > rate) rate = rt; + // } + + + // } + // } + + // #region 年时区数(NN) + // fm = GenerateCTCommand($"04000201", yearTimeZoneCount.ToString().PadLeft(2, '0')); + // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true); + // sendInfo = new SendInfo + // ( + // confirmResult.msa, + // confirmResult.cmd16, + // MeterType.Ammeter, + // CmdType.SetTimeSet, + // null, + // sDto + // ); + // si.Add(sendInfo); + // #endregion + // #region 日时段数据(NN) + // fm = GenerateCTCommand($"04000202", sDto.data.Count.ToString().PadLeft(2, '0')); + // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true); + // sendInfo = new SendInfo + // ( + // confirmResult.msa, + // confirmResult.cmd16, + // MeterType.Ammeter, + // CmdType.SetTimeSet, + // null, + // sDto + // ); + // si.Add(sendInfo); + // #endregion + // #region 日时段数(每日切换数)(NN) + // fm = GenerateCTCommand($"04000203", dayTimeZoneCount.ToString().PadLeft(2, '0')); + // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true); + // sendInfo = new SendInfo + // ( + // confirmResult.msa, + // confirmResult.cmd16, + // MeterType.Ammeter, + // CmdType.SetTimeSet, + // null, + // sDto + // ); + // si.Add(sendInfo); + // #endregion + // #region 费率数(NN) + // fm = GenerateCTCommand($"04000204", rate.ToString().PadLeft(2, '0')); + // confirmResult = GatherCmdHelper.ConrTurnData(meterInfo, fm, true); + // sendInfo = new SendInfo + // ( + // confirmResult.msa, + // confirmResult.cmd16, + // MeterType.Ammeter, + // CmdType.SetTimeSet, + // null, + // sDto + // ); + // si.Add(sendInfo); + // #endregion + // si.AddRange(tempSi); + + // tempSi.Clear(); + // // si[si.Count - 1].cmdType = CmdType.SetTimeSet;//取最后一条指令的结果返回 + //} + + #endregion + } + return bytesList; + } + /// /// 构建645协议下发命令 /// @@ -1279,81 +1932,81 @@ namespace JiShe.CollectBus.Common.Extensions /// /// 威胜表的超功率(第一路恶性负载超功率判断阀值) /// - /// + /// /// /// /// /// - public static List? AssembleWsSupperPower(string address, string password, string dataMark, decimal power) + public static List? AssembleWsSupperPower(string ammeterAddress, string password, string dataMark, decimal power) { power = Math.Round(power, 4); if (power > (decimal)99.9999) return null; var strPower = power < 10 ? $"0{power}" : power.ToString(); var pStr = strPower.Replace(".", "").PadRight(6, '0'); var data = new string[] { pStr[4] + "" + pStr[5], pStr[2] + "" + pStr[3], pStr[0] + "" + pStr[1] }; - return AssembleWrite(address, password, dataMark, data); + return AssembleWrite(ammeterAddress, password, dataMark, data); } /// /// 威胜表的超功率(超功率开关) /// - /// + /// /// /// /// - public static List AssembleWsOnSupperPower(string address, string password, bool isOn = true) + public static List AssembleWsOnSupperPower(string ammeterAddress, string password, bool isOn = true) { var data = new string[] { (isOn ? "01" : "00") }; - return AssembleWrite(address, password, "0E400001", data); + return AssembleWrite(ammeterAddress, password, "0E400001", data); } /// /// 威胜表的超功率(第一路恶性负载绝对功率判断阈值) /// - /// + /// /// /// /// /// - public static List? AssembleWsAbsolutePowerSetting(string address, string password, string dataMark, decimal power) + public static List? AssembleWsAbsolutePowerSetting(string ammeterAddress, string password, string dataMark, decimal power) { power = Math.Round(power, 4); if (power > (decimal)99.9999) return null; var strPower = power < 10 ? $"0{power}" : power.ToString(); var pStr = strPower.Replace(".", "").PadRight(6, '0'); var data = new string[] { pStr[4] + "" + pStr[5], pStr[2] + "" + pStr[3], pStr[0] + "" + pStr[1] }; - return AssembleWrite(address, password, dataMark, data); + return AssembleWrite(ammeterAddress, password, dataMark, data); } /// /// 威胜表的超功率(第一路恶性负载功率因数判断阀值) /// - /// + /// /// /// /// /// - public static List? AssembleWsPowerFactor(string address, string password, string dataMark, decimal factor) + public static List? AssembleWsPowerFactor(string ammeterAddress, string password, string dataMark, decimal factor) { factor = Math.Round(factor, 3); if (factor >= (decimal)1.0 || factor <= 0) return null; var strFactor = factor.ToString(); var pStr = strFactor.Replace(".", "").PadRight(4, '0'); var data = new string[] { pStr[2] + "" + pStr[3], pStr[0] + "" + pStr[1] }; - return AssembleWrite(address, password, dataMark, data); + return AssembleWrite(ammeterAddress, password, dataMark, data); } /// /// 构建写数据 /// - /// + /// /// /// /// /// - public static List AssembleWrite(string address, string password, string di0_3, string[] data) + public static List AssembleWrite(string ammeterAddress, string password, string di0_3, string[] data) { var returnList = new List(); returnList.Add(startStr); - var addressList = address.StringToPairs(); + var addressList = ammeterAddress.StringToPairs(); addressList.Reverse(); returnList.AddRange(addressList); @@ -1392,7 +2045,7 @@ namespace JiShe.CollectBus.Common.Extensions /// 型号编码 /// /// - private static List SoftProgram(string address,string modelCode,string password) + private static List SoftProgram(string ammeterAddress, string modelCode,string password) { string bccmd = string.Empty; if (modelCode == "DDS71") @@ -1412,7 +2065,7 @@ namespace JiShe.CollectBus.Common.Extensions var passwordStr = string.Join(" ", passwordList); bccmd = bccmd.Replace("BB BB BB", passwordStr); //替换表地址 - var addressList = address.StringToPairs(); + var addressList = ammeterAddress.StringToPairs(); addressList.Reverse(); var addressStr = string.Join(" ", addressList); bccmd = bccmd.Replace("AA AA AA AA AA AA", addressStr); @@ -1425,6 +2078,41 @@ namespace JiShe.CollectBus.Common.Extensions return fm; } + + private static List GenerateCTCommand(string ammeterAddress, string data) + { + List fm = new List(); + fm.Add(startStr); + List addressList = ammeterAddress.StringToPairs(); + addressList.Reverse(); + fm.AddRange(addressList); + fm.Add(startStr); + fm.Add("14"); + fm.Add("13"); + fm.Add("3F"); + fm.Add("34"); + fm.Add("33"); + fm.Add("37"); + fm.Add("35"); + fm.Add("33"); + fm.Add("33"); + fm.Add("33"); + fm.Add("44"); + fm.Add("44"); + fm.Add("44"); + fm.Add("44"); + //组装数据域 + var dataList = data.StringToPairs(); + dataList.Reverse(); + + fm.AddRange(dataList.AddHex33()); + + var cRC = GetCRC(fm); + fm.Add(cRC); + fm.Add(endStr); + return fm; + } + #endregion #region 188 下行命令 @@ -1591,6 +2279,26 @@ namespace JiShe.CollectBus.Common.Extensions return sum16.Substring(sum16.Length - 2, 2).ToUpper(); } + public static byte[] GetCRC16(byte[] data, bool isReverse = false) + { + int len = data.Length; + if (data == null || data.Length == 0) return new byte[] { 0, 0 }; + + ushort crc = 0xFFFF; + for (int i = 0; i < len; i++) + { + crc = (ushort)(crc ^ (data[i])); + for (int j = 0; j < 8; j++) + { + crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1); + } + } + byte hi = (byte)((crc & 0xFF00) >> 8); //高位置 + byte lo = (byte)(crc & 0x00FF); //低位置 + if (isReverse) return new byte[] { lo, hi }; + return new byte[] { hi, lo }; + } + public static object GetAnalyzeValue(this List hexStringList, CommandChunkEnum188 chunk) { if (hexStringList.Count < 11) diff --git a/src/JiShe.CollectBus.Common/Extensions/StringExtensions.cs b/src/JiShe.CollectBus.Common/Extensions/StringExtensions.cs index 8921f18..94e7421 100644 --- a/src/JiShe.CollectBus.Common/Extensions/StringExtensions.cs +++ b/src/JiShe.CollectBus.Common/Extensions/StringExtensions.cs @@ -17,7 +17,9 @@ namespace JiShe.CollectBus.Common.Extensions { public static class StringExtensions { - + private const string IPV4_REGEX = @"^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$"; + // 正则表达式用于验证端口号格式(1到65535) + private const string PORT_REGEX = @"^([1-9]\d{0,4}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$"; /// Determines whether [is null or empty]. /// The string. @@ -1082,16 +1084,20 @@ namespace JiShe.CollectBus.Common.Extensions /// 字符串分割成2个字符一组 /// /// + /// 是否翻转顺序 /// - public static List StringToPairs(this string str) + public static List StringToPairs(this string str, bool isReverse = false) { var pairs = str.Select((ch, index) => new { ch, index }) .GroupBy(x => x.index / 2) .Select(g => string.Concat(g.Select(x => x.ch))) .ToList(); + if (isReverse) + pairs.Reverse(); return pairs; } + /// /// 格式化字符串 /// @@ -1214,6 +1220,16 @@ namespace JiShe.CollectBus.Common.Extensions return rlist; } + public static bool IsValidIPv4(this string str) + { + return Regex.IsMatch(str, IPV4_REGEX); + } + + public static bool IsValidPort(this string str) + { + return Regex.IsMatch(str, PORT_REGEX); + } + private static string AddHex33(this string strGet) { string result; @@ -1248,6 +1264,15 @@ namespace JiShe.CollectBus.Common.Extensions } } + public static object TakeTimeToInt(this string timeStr) + { + var timeArr = timeStr.Split(':'); + int.TryParse(timeArr[0], out int hourInt); + int.TryParse(timeArr[1], out int minInt); + return (hourInt * 60 + minInt) / 15; + + } + private static void CreateAlphaNumMask(StringBuilder buffer, string source, char mask, int length) { for (int i = 0; i < length; i++) diff --git a/src/JiShe.CollectBus.Common/Models/ReqParameter.cs b/src/JiShe.CollectBus.Common/Models/ReqParameter.cs index 1ab3b2e..0d55825 100644 --- a/src/JiShe.CollectBus.Common/Models/ReqParameter.cs +++ b/src/JiShe.CollectBus.Common/Models/ReqParameter.cs @@ -30,6 +30,10 @@ namespace JiShe.CollectBus.Common.Models public class AmmeterParameter { + /// + /// 电能表/交流采样装置序号 + /// + public int SerialNumber { get; set; } /// /// 测量点号 0~2040 为0被删除 /// @@ -45,7 +49,8 @@ namespace JiShe.CollectBus.Common.Models /// public int Port { get; set; } - public CommunicationProtocolType ProtocolType { get; set; } + public int ProtocolType { get; set; } + //public CommunicationProtocolType ProtocolType { get; set; } /// /// 通信地址 0~999999999999 /// @@ -145,4 +150,22 @@ namespace JiShe.CollectBus.Common.Models /// public int UserSubclassNumber { get; set; } } + + public class TimeSetDetail + { + public int[] Months { get; set; } + public List Data { get; set; } + } + + public class MutileRateDetail + { + public string Rate { get; set; } + public List Times { get; set; } + } + + public class Times + { + public string StartTime { get; set; } + public string EndTime { get; set; } + } } diff --git a/src/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs b/src/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs index 27f6b4b..2f078ce 100644 --- a/src/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs +++ b/src/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs @@ -11,6 +11,7 @@ using System.Linq; using JiShe.CollectBus.Protocol.Contracts.Models; using Volo.Abp.Domain.Repositories; using System; +using MassTransit.Internals.GraphValidation; namespace JiShe.CollectBus.Protocol.Contracts.Abstracts { @@ -410,6 +411,24 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts } + /// + /// 解析终端版本信息抄读 + /// + /// + /// + /// + public virtual async Task AnalyzeTerminalVersionInfoReadingDataAsync(MessageReceivedHeartbeat messageReceived, Action? sendAction = null) + { + var hexDatas = GetHexDatas(messageReceived.MessageHexString); + + var makerNo = string.Join("",hexDatas.Take(4).Select(s => (char)s.HexToDec()));//厂商代码 + var deviceNo = string.Join("", hexDatas.Skip((int)TerminalVersionInfoEnum.DeviceNo).Take(8).Select(s => (char)s.HexToDec()));//设备编号 + var softwareVersionNo = string.Join("", hexDatas.Skip((int)TerminalVersionInfoEnum.SoftwareVersionNo).Take(4).Select(s => (char)s.HexToDec()));//软件版本号 + var softwareReleaseDateList = hexDatas.Skip((int)TerminalVersionInfoEnum.SoftwareReleaseDate).Take(3).ToList(); + var softwareReleaseDate = $"20{AnalyzeDataAccordingToA20(softwareReleaseDateList[0], softwareReleaseDateList[1], softwareReleaseDateList[2])}";//软件发布日期 + var hardwareVersionNo = string.Join("", hexDatas.Skip((int)TerminalVersionInfoEnum.HardwareVersionNo).Take(4).Select(s => (char)s.HexToDec()));//硬件版本号 + } + /// /// 解析相位角 ///