diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AutoReportCollectionItemsSetInput.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AutoReportCollectionItemsSetInput.cs index d0a5651..111b806 100644 --- a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AutoReportCollectionItemsSetInput.cs +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AutoReportCollectionItemsSetInput.cs @@ -17,7 +17,7 @@ namespace JiShe.CollectBus.EnergySystem.Dto public string GatherCode { get; set; } - public AutoReportCollectionItemsSetDetailsInput Details { get; set; } + public AutoReportCollectionItemsSetDetailsInput Detail { get; set; } } public class AutoReportCollectionItemsSetCodeInput diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AutoReportSetInput.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AutoReportSetInput.cs index d76e6e9..f2543c2 100644 --- a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AutoReportSetInput.cs +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/Dto/AutoReportSetInput.cs @@ -17,7 +17,7 @@ namespace JiShe.CollectBus.EnergySystem.Dto public string GatherCode { get; set; } - public AutoReportSetDetailsInput Details { get; set; } + public AutoReportSetDetailsInput Detail { get; set; } } public class AutoReportSetCodeInput diff --git a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/IEnergySystemAppService.cs b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/IEnergySystemAppService.cs index 4c56fb9..8ac2cba 100644 --- a/src/JiShe.CollectBus.Application.Contracts/EnergySystem/IEnergySystemAppService.cs +++ b/src/JiShe.CollectBus.Application.Contracts/EnergySystem/IEnergySystemAppService.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using JiShe.CollectBus.EnergySystem.Dto; using Volo.Abp.Application.Services; @@ -130,19 +131,19 @@ public interface IEnergySystemAppService : IApplicationService /// /// /// - Task AddConrOnlineRecord(AddConrOnlineRecordInput input); + Task AddConrOnlineRecord(List input); /// /// 记录信号强度 /// /// /// - Task AddSignalStrength(AddSignalStrengthInput input); + Task AddSignalStrength(List input); /// /// 集中器上下线、心跳记录 /// /// /// - Task AddFocusLog(AddFocusLogInput input); + Task AddFocusLog(List 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 df2c6e1..509f113 100644 --- a/src/JiShe.CollectBus.Application/EnergySystem/EnergySystemAppService.cs +++ b/src/JiShe.CollectBus.Application/EnergySystem/EnergySystemAppService.cs @@ -5,6 +5,7 @@ using System.Net; using System.Text; using System.Threading.Tasks; using DotNetCore.CAP; +using JiShe.CollectBus.Common.BuildSendDatas; using JiShe.CollectBus.Common.Enums; using JiShe.CollectBus.Common.Extensions; using JiShe.CollectBus.Common.Models; @@ -55,9 +56,9 @@ namespace JiShe.CollectBus.EnergySystem if (ammeter == null) return result; var dataUnit = - HexStringExtensions.BuildAmmeterValveControlSendDataUnit(ammeter.Address, "", ammeter.Password, + Build645SendData.BuildAmmeterValveControlSendDataUnit(ammeter.Address, "", ammeter.Password, state); - bytes = HexStringExtensions.BuildTransparentForwardingSendCmd(address, ammeter.PortNumber ?? 2, ammeter.BaudRate, dataUnit); + bytes = Build3761SendData.BuildTransparentForwardingSendCmd(address, ammeter.PortNumber ?? 2, ammeter.BaudRate, dataUnit); } else if(input.MeterType == 2) { @@ -100,7 +101,7 @@ namespace JiShe.CollectBus.EnergySystem if (ammeter == null) return result; var address = $"{input.AreaCode}{input.Address}"; - var bytesList = HexStringExtensions.BuildReadMeterTimeSetSendCmd(address, ammeter.Code, ammeter.Address, ammeter.Password, + var bytesList = Build3761SendData.BuildReadMeterTimeSetSendCmd(address, ammeter.Code, ammeter.Address, ammeter.Password, ammeter.PortNumber ?? 2, ammeter.BaudRate); foreach (var bytes in bytesList) @@ -132,9 +133,9 @@ namespace JiShe.CollectBus.EnergySystem { SerialNumber = it.SerialNumber, Pn = it.Pn, - BaudRate = HexStringExtensions.GetBaudreate(it.Rate.ToString()), + BaudRate = Build3761SendData.GetBaudreate(it.Rate.ToString()), Port = it.Port, - ProtocolType = HexStringExtensions.GetProtocolType(it.AgreementType), + ProtocolType = Build3761SendData.GetProtocolType(it.AgreementType), Address = it.Addrress, Password = it.Password.ToString(), RateNumber = it.RatesCount, @@ -145,7 +146,7 @@ namespace JiShe.CollectBus.EnergySystem //UserSubclassNumber = it.UserSmallNumber }).ToList(); - var bytes = HexStringExtensions.BuildAmmeterParameterSetSendCmd(address, meterParameters); + var bytes = Build3761SendData.BuildAmmeterParameterSetSendCmd(address, meterParameters); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { //ClientId = messageReceived.ClientId, @@ -167,9 +168,27 @@ namespace JiShe.CollectBus.EnergySystem /// /// [Route("Handmould/ReadMeterAddress_10_105")] - public Task AmmeterArchivesMatch(AmmeterArchivesMatchInput input) + public async Task AmmeterArchivesMatch(AmmeterArchivesMatchInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + var address = $"{input.AreaCode}{input.Address}"; + foreach (var detail in input.Details.Data) + { + var dataUnit = Build645SendData.BuildReadMeterAddressSendDataUnit(detail.MeterAddress); + var bytes =Build3761SendData.BuildTransparentForwardingSendCmd(address, detail.Port, detail.BaudRate.ToString(), dataUnit, StopBit.Stop1, Parity.None); + 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; } /// @@ -202,7 +221,7 @@ namespace JiShe.CollectBus.EnergySystem return result; } - var bytes = HexStringExtensions.BuildCommunicationParametersSetSendCmd(address, masterIP, materPort, + var bytes = Build3761SendData.BuildCommunicationParametersSetSendCmd(address, masterIP, materPort, backupIP, backupPort, input.Data.APN); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { @@ -230,7 +249,7 @@ namespace JiShe.CollectBus.EnergySystem var result = new BaseResultDto(); var address = $"{input.AreaCode}{input.Address}"; - var bytes = HexStringExtensions.BuildTerminalCalendarClockSendCmd(address); + var bytes = Build3761SendData.BuildTerminalCalendarClockSendCmd(address); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { //ClientId = messageReceived.ClientId, @@ -257,7 +276,7 @@ namespace JiShe.CollectBus.EnergySystem var result = new BaseResultDto(); var address = $"{input.AreaCode}{input.Address}"; - var bytes = HexStringExtensions.BuildConrCheckTimeSendCmd(address,DateTime.Now); + var bytes = Build3761SendData.BuildConrCheckTimeSendCmd(address,DateTime.Now); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { //ClientId = messageReceived.ClientId, @@ -284,7 +303,7 @@ namespace JiShe.CollectBus.EnergySystem var result = new BaseResultDto(); var address = $"{input.AreaCode}{input.Address}"; - var bytes = HexStringExtensions.BuildConrRebootSendCmd(address); + var bytes = Build3761SendData.BuildConrRebootSendCmd(address); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { //ClientId = messageReceived.ClientId, @@ -312,7 +331,7 @@ namespace JiShe.CollectBus.EnergySystem var address = $"{input.AreaCode}{input.Address}"; var pnList = input.Data.Split(',').Select(it => int.Parse(it)).ToList(); - var bytes = HexStringExtensions.BuildAmmeterParameterReadingSendCmd(address, pnList); + var bytes = Build3761SendData.BuildAmmeterParameterReadingSendCmd(address, pnList); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { //ClientId = messageReceived.ClientId, @@ -349,13 +368,13 @@ namespace JiShe.CollectBus.EnergySystem var fn = int.Parse(itemCodeArr[1]); if (aFN == AFN.请求实时数据) { - var bytes = HexStringExtensions.BuildAmmeterReadRealTimeDataSendCmd(address, ammeter.MeterCode.Value, (ATypeOfDataItems)fn); + var bytes = Build3761SendData.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); + var bytes = Build3761SendData.BuildAmmeterReadingIIdataTypeItemsSendCmd(address, ammeter.MeterCode.Value, (IIdataTypeItems)fn, density,0); bytesList.Add(bytes); } } @@ -391,6 +410,27 @@ namespace JiShe.CollectBus.EnergySystem var ammeter = await SqlProvider.Instance.Change(DbEnum.EnergyDB).Select().Where(d => d.ID == input.MeterID).FirstAsync(); if (ammeter == null) return result; + //if (string.IsNullOrEmpty(ammeter.BrandType)) + //{ + // resultMsg.Status = false; + // resultMsg.Msg = "电表型号为空"; + // return resultMsg; + //} + //var listData = ProgramModelConfig.ProgramModels; + //var pm = listData.FirstOrDefault(n => n.Model == ammeter.BrandType); + //if (pm == null) + //{ + // resultMsg.Status = false; + // resultMsg.Msg = $"电表{ammeter.AmmerterAddress}型号{ammeter.BrandType}暂不支持时段设置"; + // return resultMsg; + //} + + //resultMsg.Status = true; + //if (pm.IsEnter) + //{ + // resultMsg.Data = pm.cmdData; + //} + var address = input.FocusCode; var timeDataList = input.Data.Select(it => new TimeSetDetail() { @@ -405,7 +445,7 @@ namespace JiShe.CollectBus.EnergySystem }).ToList() }).ToList() }).ToList(); - var bytesList = HexStringExtensions.BuildAmmeterSetTimeSetSendCmd(address, ammeter.Code, ammeter.Address, + var bytesList = Build3761SendData.BuildAmmeterSetTimeSetSendCmd(address, ammeter.Code, ammeter.Address, ammeter.PortNumber ?? 2, ammeter.BaudRate, timeDataList); foreach (var bytes in bytesList) @@ -431,9 +471,26 @@ namespace JiShe.CollectBus.EnergySystem /// /// [Route("Handmould/SetAutoItemCode")] - public Task AutoReportCollectionItemsSet(AutoReportCollectionItemsSetInput input) + public async Task AutoReportCollectionItemsSet(AutoReportCollectionItemsSetInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + foreach (var code in input.Codes) + { + var address = $"{code.AreaCode}{code.Address}"; + var bytes = Build3761SendData.BuildAmmeterReportCollectionItemsSetSendCmd(address,input.Detail.Pn, input.Detail.Unit,input.Detail.Cycle,input.Detail.BaseTime, + input.Detail.CurveRatio,input.Detail.Details.Select(it => new PnFn(it.Pn,it.Fn)).ToList()); + 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; } /// @@ -443,21 +500,50 @@ namespace JiShe.CollectBus.EnergySystem /// /// [Route("Handmould/SetAutoUpSwitch")] - public Task AutoReportSet(AutoReportSetInput input) + public async Task AutoReportSet(AutoReportSetInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + foreach (var code in input.Codes) + { + var address = $"{code.AreaCode}{code.Address}"; + var bytes = Build3761SendData.BuildAmmeterAutoUpSwitchSetSendCmd(address, input.Detail.Pn,input.Detail.IsOpen); + 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; } /// - /// 查询自动上报开启状态 数据库操作 + /// 查询自动上报开启状态 /// /// /// /// [Route("Handmould/QueryAutoUpSwitch")] - public Task QueryAutoReportOpenStatus(QueryAutoReportOpenStatusInput input) + public async Task QueryAutoReportOpenStatus(QueryAutoReportOpenStatusInput input) { - throw new NotImplementedException(); + var result = new BaseResultDto(); + var address = $"{input.AreaCode}{input.Address}"; + var bytes = Build3761SendData.BuildAmmeterReadAutoUpSwitchSendCmd(address, input.Detail.Pn); + 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; } /// @@ -473,7 +559,7 @@ namespace JiShe.CollectBus.EnergySystem foreach (var data in input.Data) { var address = $"{data.AreaCode}{data.Address}"; - var bytes = HexStringExtensions.BuildTerminalVersionInfoReadingSendCmd(address); + var bytes = Build3761SendData.BuildTerminalVersionInfoReadingSendCmd(address); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { //ClientId = messageReceived.ClientId, @@ -510,13 +596,22 @@ namespace JiShe.CollectBus.EnergySystem 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); + + var bytesList = new List(); + var dateDataUnit = + Build645SendData.BuildAmmeterCorrectionTimeSendDataUnit(input.MeterAddress, input.Password, + "04 00 01 01", 0); + var dateBytes = Build3761SendData.BuildTransparentForwardingSendCmd(address, input.Port, input.BaudRate.ToString(), + dateDataUnit); + bytesList.Add(dateBytes); + + var timeDataUnit = + Build645SendData.BuildAmmeterCorrectionTimeSendDataUnit(input.MeterAddress, input.Password, + "04 00 01 02", 0); + var timeBytes = Build3761SendData.BuildTransparentForwardingSendCmd(address, input.Port, input.BaudRate.ToString(), + timeDataUnit); + bytesList.Add(timeBytes); foreach (var bytes in bytesList) { @@ -542,10 +637,10 @@ namespace JiShe.CollectBus.EnergySystem /// /// [Route("AfterSaleApi/AddConrOnlineRecord")] - public async Task AddConrOnlineRecord(AddConrOnlineRecordInput input) + public async Task AddConrOnlineRecord(List input) { - var conrOnlineRecord = new ConrOnlineRecord(input.AreaCode,input.Address,input.State,input.LastTime); - await _conrOnlineRecordRepository.InsertAsync(conrOnlineRecord); + var conrOnlineRecords = input.Select(it => new ConrOnlineRecord(it.AreaCode, it.Address, it.State, it.LastTime)).ToList(); + await _conrOnlineRecordRepository.InsertManyAsync(conrOnlineRecords); return new BaseResultDto() { Status = true @@ -559,10 +654,11 @@ namespace JiShe.CollectBus.EnergySystem /// /// [Route("AfterSaleApi/RssiToWebApi")] - public async Task AddSignalStrength(AddSignalStrengthInput input) + public async Task AddSignalStrength(List input) { - var csqRecord = new CsqRecord(input.Address, input.AreaCode,input.DeviceType,input.Csq); - await _csqRecordRepository.InsertAsync(csqRecord); + var csqRecords = input.Select(it => + new CsqRecord(it.Address, it.AreaCode, it.DeviceType, it.Csq)).ToList(); + await _csqRecordRepository.InsertManyAsync(csqRecords); return new BaseResultDto() { @@ -577,11 +673,13 @@ namespace JiShe.CollectBus.EnergySystem /// /// [Route("AfterSaleApi/AddFocusLog")] - public async Task AddFocusLog(AddFocusLogInput input) + public async Task AddFocusLog(List input) { - var focusLog = new FocusRecord(input.Address, input.GatherServerId, int.Parse(input.IntervalTime), input.LogTime, - input.LogType, input.Remark); - await _focusRecordRepository.InsertAsync(focusLog); + var focusLogs = input.Select(it => + new FocusRecord(it.Address, it.GatherServerId, int.Parse(it.IntervalTime), it.LogTime, + it.LogType, it.Remark)).ToList(); + + await _focusRecordRepository.InsertManyAsync(focusLogs); return new BaseResultDto() { diff --git a/src/JiShe.CollectBus.Common/BuildSendDatas/Build188SendData.cs b/src/JiShe.CollectBus.Common/BuildSendDatas/Build188SendData.cs new file mode 100644 index 0000000..5fb9e3b --- /dev/null +++ b/src/JiShe.CollectBus.Common/BuildSendDatas/Build188SendData.cs @@ -0,0 +1,213 @@ +using JiShe.CollectBus.Common.Enums; +using JiShe.CollectBus.Common.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JiShe.CollectBus.Common.BuildSendDatas +{ + public static class Build188SendData + { + //起始字符 + private const string startStr = "68"; + + //结束字符 + private const string endStr = "16"; + + #region 188 下行命令 + + /// + /// 标准 188协议阀控 + /// + /// + /// 表计类型 + /// + public static List BuildConfirm188WaterValve(string waterMeterAddress, bool state, string mtype = "10") + { + if (string.IsNullOrWhiteSpace(waterMeterAddress)) return null; + + var dataUnit = new List() { "A0", "17", "00", state ? "55" : "99" }; + + var dataList = Build188SendCommand(waterMeterAddress, "04", dataUnit); + + return dataList; + } + + /// + /// 构建188水表抄读下发数据单元 + /// + /// + /// + public static List Build188WaterMeterReadingSendDataUnit(string waterMeterAddress) + { + + var dataUnit = new List() { "1F", "90", "00" }; + var dataList = Build188SendCommand(waterMeterAddress, "01", dataUnit); + + return dataList; + } + + /// + /// 构建188协议下发命令 + /// + /// 水表地址 + /// 控制码 + /// 数据域 + /// 表类型 + /// + public static List Build188SendCommand(string waterMeterAddress, string controlCode, List? dataUnit = null, string meterType = "10") + { + //address.Substring(address.Length - 12, 12) + var cmdStrList = new List(); + cmdStrList.Add(startStr); + cmdStrList.Add(meterType); + + waterMeterAddress = waterMeterAddress.PadLeft(14, '0'); + var addressList = waterMeterAddress.StringToPairs(); + addressList.Reverse(); + cmdStrList.AddRange(addressList); + + //控制码 + cmdStrList.Add(controlCode); + + var len = dataUnit != null ? dataUnit.Count.DecToHex().PadLeft(2, '0') : "00"; + cmdStrList.Add(len); + if (dataUnit != null) + { + cmdStrList.AddRange(dataUnit); + } + + var strSum = cmdStrList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); + strSum = strSum.Substring(strSum.Length - 2); + cmdStrList.Add(strSum); + cmdStrList.Add(endStr); + + return cmdStrList; + } + + /// + /// 组装水表阀控 + /// + /// 水表地址 + /// The password. + /// The poprotocol. + /// if set to true [isopenvalve]. + /// + public static List? WaterMeterValveControl(string waterMeterAddress, string password, int protocol, bool state) + { + List? turnData = null; + if (protocol == 1) + turnData = GetControlCode97(waterMeterAddress.Substring(waterMeterAddress.Length - 12, 12), password, state ? "3355" : "9966");//开阀/关阀 + else if (protocol == 30) + turnData = GetControlCode07(waterMeterAddress.Substring(waterMeterAddress.Length - 12, 12), password, state ? "3355" : "9966");//开阀/关阀 + return turnData; + } + + private static List GetControlCode97(string waterMeterAddress, string password, string valueCode) + { + var dataList = new List(); + var passwordList = password.StringToPairs(); + passwordList.Reverse(); + + var valueCodeList = valueCode.StringToPairs(); + valueCodeList.Reverse(); + + dataList.AddRange(valueCodeList); + dataList.AddRange(passwordList); + dataList.AddRange(valueCodeList); + + return GetCode(waterMeterAddress, "04", dataList); + } + + private static List GetControlCode07(string waterMeterAddress, string password, string valueCode) + { + var dataList = new List(); + dataList.Add("02"); + + var passwordList = password.StringToPairs(); + passwordList.Reverse(); + dataList.AddRange(passwordList); + dataList.AddRange("01000000".StringToPairs()); + + dataList.AddRange(valueCode.StringToPairs()); + + dataList.Add("00"); + + var time = DateTime.Now.AddDays(1).ToString("yyMMddHHmmss"); + var timeList = time.StringToPairs(); + timeList.Reverse(); + dataList.AddRange(timeList); + + return GetCode(waterMeterAddress, "1C", dataList); + } + + public static List GetCode(string waterMeterAddress, string controlCode, List childDataList) + { + var dataList = new List { startStr }; + + waterMeterAddress = waterMeterAddress.PadLeft(12, '0'); + var addressList = waterMeterAddress.StringToPairs(); + addressList.Reverse(); + dataList.AddRange(addressList); + + dataList.Add(startStr); + dataList.Add(controlCode); + + var num = childDataList.Count; + dataList.Add(num.ToString("X2")); + + dataList.AddRange(childDataList.AddHex33()); + + var cs = dataList.Select(it => Convert.ToInt32(it, 16)).Sum().ToString("X2"); + cs = cs.Substring(cs.Length - 2, 2); + dataList.Add(cs); + + dataList.Add(endStr); + + return dataList; + } + + + public static object GetAnalyzeValue(this List hexStringList, CommandChunkEnum188 chunk) + { + if (hexStringList.Count < 11) + { + return null; + } + + switch (chunk) + { + case CommandChunkEnum188.A: + var aHexList = hexStringList[(int)CommandChunkEnum188.A].Take(7).ToList(); + aHexList.Reverse(); + return string.Join("", aHexList.Skip(1).Take(6).ToList()); + case CommandChunkEnum188.C: + var cHex = hexStringList[(int)CommandChunkEnum188.C]; + return cHex; + case CommandChunkEnum188.Data: + var lenIndex = (int)CommandChunkEnum188.L; + var len = hexStringList[lenIndex].HexToDec(); + + //验证长度 2=(帧校验和+结束字符) + if (hexStringList.Count - 2 != 11 + len) + return null; + + var dataHexList = hexStringList.Skip(11).Take(len).ToList(); + return dataHexList; + default: + throw new ArgumentOutOfRangeException(nameof(chunk), chunk, null); + } + } + + //public double AnalyzeCurrentTotalRate(List hexList) + //{ + // var str = string.Join("", hexList); + // var number = Convert.ToInt32(str) * 0.01; + // return number; + //} + + #endregion + } +} diff --git a/src/JiShe.CollectBus.Common/BuildSendDatas/Build3761SendData.cs b/src/JiShe.CollectBus.Common/BuildSendDatas/Build3761SendData.cs new file mode 100644 index 0000000..224c242 --- /dev/null +++ b/src/JiShe.CollectBus.Common/BuildSendDatas/Build3761SendData.cs @@ -0,0 +1,1650 @@ +using JiShe.CollectBus.Common.Enums; +using JiShe.CollectBus.Common.Extensions; +using JiShe.CollectBus.Common.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; + +namespace JiShe.CollectBus.Common.BuildSendDatas +{ + public static class Build3761SendData + { + //起始字符 + private const string startStr = "68"; + //结束字符 + private const string endStr = "16"; + //头部字节长度 + private const int hearderLen = 6; + //消息认证码字段长度 + private const int pWLen = 16; + + private const int FixedLength = 18; + + static object locker = new object(); + static List MSA = new List(); + static Dictionary> usingMSA = new Dictionary>(); + + static Build3761SendData() + { + for (int i = 1; i <= 127; i++) + { + MSA.Add(i); + } + } + /// + /// Gets the msa. + /// + /// 集中器地址 + /// + public static int GetMSA(string mark) + { + lock (locker) + { + if (!usingMSA.Keys.Contains(mark)) + usingMSA.Add(mark, new List()); + + int msa = MSA.Except(usingMSA[mark]).FirstOrDefault(); + //if (msa == 1) msa = 2;//msa=1为自定义指令保留 + usingMSA[mark].Add(msa); + + if (msa == 127) + usingMSA[mark].RemoveAll(m => true); + + return msa; + } + } + + + #region 376.1下行命令 + + /// + /// 构建电表修正时间下发命令 + /// + /// + /// + /// + /// + /// + /// + /// + public static List BuildAmmeterCorrectionTimeSendCmd(string address, string modelCode, string ammeterAddress, string password, int port, string baudRate) + { + var bytesList = new List(); + if (modelCode == "PMAC9523") + { + var dataUnit = Build645SendData.BuildPMAC9523AmmeterCorrectionTimeSendDataUnit(ammeterAddress); + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit, StopBit.Stop1, Parity.None); + bytesList.Add(bytes); + } + else if (modelCode == "DTSU193") + { + var dataUnit = Build645SendData.BuildDTSU193AmmeterCorrectionTimeSendDataUnit(ammeterAddress); + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit); + bytesList.Add(bytes); + } + else + { + var dataUnitList = Build645SendData.BuildAmmeterCorrectionTimeSendDataUnit(ammeterAddress,password); + foreach (var dataUnit in dataUnitList) + { + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit); + 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") + { + var dataUnit = Build645SendData.BuildPMAC9523ReadMeterTimeSetSendDataUnit(ammeterAddress); + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit, StopBit.Stop1, Parity.None); + return new List() { bytes }; + } + + var bytes1 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010001")); + + var bytes2 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010002")); + + var bytes3 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010003")); + + var bytes4 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010004")); + + var bytes9 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04010005")); + + var bytes5 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020001")); + + var bytes6 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020002")); + + var bytes7 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020003")); + + var bytes8 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020004")); + + var bytes10 = BuildTransparentForwardingSendCmd(address, port, baudRate, + Build645SendData.BuildAmmeterReadDataUnit(ammeterAddress, CmdType.ReadTimeSet, "04020005")); + + + return new List { bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7, bytes8, bytes9, bytes10 }; + } + + + /// + /// 构建设置时段下发命令 + /// + /// + /// + /// + /// + /// + /// + /// + 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 dataUnitList = Build645SendData.BuildPMAC9523AmmeterSetTimeSetSendDataUnit(ammeterAddress, data); + foreach (var dataUnit in dataUnitList) + { + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit, 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; + } + + + /// + /// 构建电表参数设置-下发命令 + /// + /// 集中器地址 + /// + /// + public static byte[] BuildAmmeterParameterSetSendCmd(string address, List meterParameters) + { + var dataUnit = BuildAmmeterParameterSendDataUnit(meterParameters); + 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 = 10 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; + } + + /// + /// 构建电表参数读取-下发命令 + /// + /// 集中器地址 + /// 对象序号 + public static byte[] BuildAmmeterParameterReadingSendCmd(string address, List meterNumberList) + { + var dataUnit = new List(); + var countHex = meterNumberList.Count().DecToHex().PadLeft(4, '0'); + var countHexPairs = countHex.StringToPairs(); + countHexPairs.Reverse(); + dataUnit.AddRange(countHexPairs); + + foreach (var number in meterNumberList) + { + var numberHex = number.DecToHex().PadLeft(4, '0'); + var numberHexPairs = numberHex.StringToPairs(); + numberHexPairs.Reverse(); + dataUnit.AddRange(numberHexPairs); + } + + var reqParameter = new ReqParameter2() + { + AFN = AFN.查询参数, + FunCode = (int)CMasterStationFunCode.请求2级数据, + A = address, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.不需要对该帧进行确认, + PRSEQ = 0, + }, + MSA = GetMSA(address), + Pn = 0, + Fn = 10 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; + } + + /// + /// 构建电表抄读一类数据-下发命令 + /// + /// + /// + /// 一类数据项 + public static byte[] BuildAmmeterReadRealTimeDataSendCmd(string address, int pn, ATypeOfDataItems aTypeOfDataItems) + { + 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 = pn, + Fn = (int)aTypeOfDataItems + }; + var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter); + return bytes; + } + + /// + /// 构建电表抄读日冻结正向有功电能示值-下发命令 + /// + /// + /// + /// + public static void BuildAmmeterReadDailyFreezingDataSendCmd(string address, int pn, DateTime time) + { + var dataUnit = time.ToString("yy-MM-dd").Split('-').ToList(); + dataUnit.Reverse(); + 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 = pn, + Fn = 161 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + } + + /// + /// 构建电表抄读实时电流-下发命令 + /// + /// + /// + public static void BuildAmmeterRealTimeCurrentDataSendCmd(string address, int pn) + { + 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 = pn, + Fn = 25 + }; + var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter); + } + + /// + /// 构建自动上报开启状态读取-下发命令 + /// + /// 集中器地址 + /// + /// + public static byte[] BuildAmmeterReadAutoUpSwitchSendCmd(string address, int pn) + { + 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 = pn, + Fn = 68 + }; + var bytes = BuildSendCommandBytes(reqParameter); + return bytes; + } + + /// + /// 构建自动上报开启状态设置-下发命令 + /// + /// 集中器地址 + /// + /// + /// + public static byte[] BuildAmmeterAutoUpSwitchSetSendCmd(string address, int pn,bool isOpen) + { + var dataUnit = new List(){ isOpen ? "55" : "AA" };//自动上报任务命令字节 + 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 = pn, + Fn = 68 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; + } + + + /// + /// 构建自动上报采集项设置-下发命令 + /// + /// 集中器地址 + /// 计量点 + /// 定时发送周期(单位) + /// 定时发送周期 1:用 D6~D7 编码表示,取值 0~3 依次表示分、时、日、月 2:用 D0~D5 表示,为定时上报数据的时间周期 + /// 发送基准时间 + /// 曲线数据提取倍率 + /// + /// + public static byte[] BuildAmmeterReportCollectionItemsSetSendCmd(string address, int pn,int unit,int cycle,DateTime baseTime,int curveRatio,List pnFns) + { + List dataUnit = new List(); + + var cycleSb = $"{unit.DecToBin()}{cycle.DecToBin()}"; + dataUnit.Add(cycleSb.BinToHex().PadLeft(2, '0')); + dataUnit.AddRange(baseTime.ToString("ssmmHHddMMyy").StringToPairs());//发送基准时间 + dataUnit.Add(curveRatio.DecToHex().PadLeft(2, '0'));//曲线数据提取倍率 + dataUnit.Add(pnFns.Count.DecToHex().PadLeft(2, '0'));//数据单元标识个数 n + + foreach (var item in pnFns) + { + dataUnit.AddRange(BuildDA(item.Pn));//单元数据标记、单元数据 + dataUnit.AddRange(BuildDT(item.Fn));//单元数据标记、单元数据 + } + + 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 = pn, + Fn = 66 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; + } + + /// + /// 构建电表读取二类数据-下发命令 + /// + /// + /// + /// fn + /// 冻结密度 + /// 冻结点数 + /// 起始时间 + public static byte[] BuildAmmeterReadingIIdataTypeItemsSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, FreezeDensity density, int points, DateTime? beginTime = null) + { + var queryDate = beginTime ?? DateTime.Today.AddDays(-1); + var dataUnit = queryDate.ToString("yyMMddHHmm").StringToPairs(); + dataUnit.Reverse(); + + //冻结密度 + dataUnit.Add(((int)density).DecToHex()); + + dataUnit.Add(points.DecToHex()); + + 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 = pn, + Fn = (int)iIDataTypeItems + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + return bytes; + } + + /// + /// 构建电表读取二类数据-下发命令 + /// + /// + /// + /// fn + /// 数据时标 + /// 起始时间 + public static void BuildAmmeterReadingBaseDataSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, TdType tdType, DateTime? beginTime = null) + { + var queryDate = beginTime ?? DateTime.Today.AddDays(-1); + List? dataUnit = null; + switch (tdType) + { + case TdType.Td_d: + dataUnit = queryDate.ToString("yyMMdd").StringToPairs(); + break; + case TdType.Td_m: + dataUnit = queryDate.ToString("yyMM").StringToPairs(); + break; + } + + if (dataUnit == null) return; + + dataUnit.Reverse(); + 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 = pn, + Fn = (int)iIDataTypeItems + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + } + + + /// + /// 组装有/无功电量 + /// + /// + /// + /// + public static void BuildAmmeterReadingElectricityDataSendCmd(string address, int pn, int cmdType) + { + 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 = pn, + Fn = cmdType + }; + var bytes = Build3761SendData.BuildSendCommandBytes(reqParameter); + } + + /// + /// 构建超功率设置-下发命令 + /// + /// + /// + /// + /// + /// + /// + public static void BuildAmmeterSuperpowerSettingSendCmd(string address, string password, string modelCode, int port, string baudRate, decimal power) + { + if (power > 0) + { + + WsOnSupperPower(address, password, modelCode, true, port, baudRate); + + //TODO:连续发几条嘛? + string dataMark; + //如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001 + if (address.IndexOf('_') > 0) + { + var addressSplit = address.Split('_'); + address = addressSplit[0]; + var loop = Convert.ToInt32(addressSplit[1]); + if (loop == 1) { dataMark = "0E300101"; } + else if (loop == 2) { dataMark = "0E300201"; } + else + return; + } + else + { + dataMark = "0E300101"; + } + + var turnData = Build645SendData.AssembleWsSupperPower(address, password, dataMark, power); + if (turnData != null) + { + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData); + } + } + else + { + WsOnSupperPower(address, password, modelCode, false, port, baudRate); + } + + } + + /// + /// 构建恶性负载绝对功率设置-下发命令 + /// + /// + /// + /// + /// + /// + public static void BuildAmmeterAbsolutePowerSettingSendCmd(string address, string password, int port, string baudRate, decimal power) + { + if (power <= 0) + { + power = 99;//等于小0 代表关闭 + } + + string dataMark; + //如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001 + if (address.IndexOf('_') > 0) + { + var addressSplit = address.Split('_'); + address = addressSplit[0]; + + var loop = Convert.ToInt32(addressSplit[1]); + if (loop == 1) { dataMark = "0E300103"; } + else if (loop == 2) { dataMark = "0E300203"; } + else + return; + } + else + { + dataMark = "0E300103"; + } + + var turnData = Build645SendData.AssembleWsAbsolutePowerSetting(address, password, dataMark, power); + if (turnData != null) + { + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData); + } + } + + /// + /// 构建恶性负载功率因数设置-下发命令 + /// + /// + /// + /// + /// + /// + public static void BuildAmmeterPowerFactorSettingSendCmd(string address, string password, int port, string baudRate, decimal power) + { + string dataMark; + //如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001 + if (address.IndexOf('_') > 0) + { + var addressSplit = address.Split('_'); + address = addressSplit[0]; + + var loop = Convert.ToInt32(addressSplit[1]); + if (loop == 1) { dataMark = "0E300104"; } + else if (loop == 2) { dataMark = "0E300204"; } + else + return; + } + else + { + dataMark = "0E300104"; + } + + var turnData = Build645SendData.AssembleWsPowerFactor(address, password, dataMark, power); + if (turnData != null) + { + var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData); + } + } + + /// + /// 超功率开关 + /// + /// + /// + /// + /// + /// + 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" }; + //这些型号需进入软编程 + if (modelCodes.Contains(modelCode)) + { + var dataUnit1 = Build645SendData.SoftProgram(address, modelCode, password); + BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit1); + } + + var dataUnit2 = Build645SendData.AssembleWsOnSupperPower(address, password, isOn); + BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit2); + } + + /// + /// 构建水表参数设置-下发命令 + /// + /// 集中器地址 + /// + /// + public static byte[] BuildWaterMeterParameterSetSendCmd(string address, List meterParameters) + { + var dataUnit = BuildWaterMeterParameterSendDataUnit(meterParameters); + 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 = 10 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + 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 = Build3761SendData.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 = 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 + /// 300,600,1200,2400,4800,7200,9600,19200对应 0~7 + /// 转发内容 + /// 停止位 + /// 校验方式 + /// 数据位 + /// 等待报文超时时间/s + /// 等待字节超时时间/ms + 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 baudRateValue = GetBaudreate(baudRate); + + var dataUnit = BuildTransparentForwardingSendDataUnit(port, baudRateValue, datas, stopBit, parity, dataBit, waitContentTimeout, waitByteTimeout); + dataUnit.AddRange(GetPW()); + var reqParameter = new ReqParameter2() + { + AFN = AFN.数据转发, + FunCode = (int)CMasterStationFunCode.请求2级数据, + A = address, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.不需要对该帧进行确认, + PRSEQ = 0 + }, + MSA = GetMSA(address), + Pn = 0, + Fn = 1 + }; + var bytes = BuildSendCommandBytes(reqParameter, dataUnit); + 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 = "") + { + address = address.Trim().TrimStart('0'); + if (address.Length < 12) address = address.PadLeft(12, '0'); + string Code = string.Empty; + + if (state) + { + if (string.IsNullOrEmpty(specialnocode)) + Code = "1B"; + else + Code = specialnocode == "1B" || specialnocode == "1C" ? specialnocode : "1C"; + } + else + Code = "1A";//跳闸 + + if (specialnocode == "1W") + { + if (state) + Code = "1A"; + else + Code = "1C"; + } + + var pwdLevel = "02"; + if (modelCode == "HL_DTSU2625" || modelCode == "DDZY9866") + pwdLevel = "04"; + else if (modelCode == "DDS2705") + pwdLevel = "03"; + + if (!string.IsNullOrWhiteSpace(password) && password.Contains("|")) + { + var sp = password.Split('|'); + pwdLevel = sp[1]; + password = sp[0]; + } + + string strDate = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan(); + if (specialnocode == "1D" || modelCode == "SZBD_DDZY1225") + strDate = "FF FF FF FF FF FF"; + string strP = password.StrAddSpan().StrReverseOrder(); + string strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + Code + " 00 " + strDate; + string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2"); + string strReturn = "68 " + address.StrAddSpan().StrReverseOrder() + " 68 1C " + strLen + " " + strSJY.StrAddHex33() + " "; + string strSum = strReturn.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); + strReturn += strSum.Substring(strSum.Length - 2) + " 16"; + + return strReturn.Split(' ').ToList(); + } + + + /// + /// 构建透明转发-下发数据单元 + /// + /// 终端通信端口 1~31 + /// 0~7 对应300,600,1200,2400,4800,7200,9600,19200 + /// 转发内容 + /// 停止位 + /// 校验方式 + /// 数据位 + /// 等待报文超时时间/s + /// 等待字节超时时间/ms + /// + 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(); + + var portHex = port.DecToHex().PadLeft(2, '0'); + dataUnit.Add(portHex); + + 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'); + var controlHex = $"{baudRateBin}{stopBitBin}{parityBin}{dataBitBin}".BinToHex().PadLeft(2, '0'); ; + dataUnit.Add(controlHex); + + var waitContentTimeoutBin = $"1{waitContentTimeout.DecToBin().PadLeft(7, '0')}"; + var waitContentTimeoutHex = waitContentTimeoutBin.BinToHex().PadLeft(2, '0'); + var waitByteTimeoutHex = waitByteTimeout.DecToHex().PadLeft(2, '0'); + + dataUnit.Add(waitContentTimeoutHex); + dataUnit.Add(waitByteTimeoutHex); + + var countHex = datas.Count.DecToHex().PadLeft(4, '0'); + var countHexPairs = countHex.StringToPairs(); + countHexPairs.Reverse(); + dataUnit.AddRange(countHexPairs); + + dataUnit.AddRange(datas); + + return dataUnit; + } + + /// + /// 构建下发命令 + /// + /// + /// + /// + public static byte[] BuildSendCommandBytes(ReqParameter reqParameter, List? dataUnit = null) + { + var cmdStrList = new List(); + var userDatas = BuildUserData(reqParameter, dataUnit); + var hearders = BuildHeaders(userDatas.Count); + var cs = GetCS(userDatas); + cmdStrList.AddRange(hearders); + cmdStrList.AddRange(userDatas); + cmdStrList.Add(cs); + cmdStrList.Add(endStr); + Console.WriteLine(string.Join(" ", cmdStrList)); + var bytes = cmdStrList.Select(x => Convert.ToByte(x, 16)).ToArray(); + return bytes; + } + + /// + /// 构建电表参数设置-下发数据单元 + /// + /// + /// + private static List BuildAmmeterParameterSendDataUnit(List meterParameters) + { + var hexDatas = new List(); + + var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0'); + hexDatas.Add(countHex); + + for (int i = 0; i <= meterParameters.Count - 1; i++) + { + var meter = meterParameters[i]; + + //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'); + hexDatas.Add(pnHex); + + var baudRateBin = meter.BaudRate.DecToBin().PadLeft(3, '0'); + var portBin = meter.Port.DecToBin().PadLeft(5, '0'); + var baudRateAndPortHex = $"{baudRateBin}{portBin}".BinToHex().PadLeft(2, '0'); + hexDatas.Add(baudRateAndPortHex); + + var protocolTypeHex = ((int)meter.ProtocolType).DecToHex().PadLeft(2, '0'); + hexDatas.Add(protocolTypeHex); + + hexDatas.Add(meter.Address); + + hexDatas.Add(meter.Password.PadLeft(12, '0')); + + var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}"; + var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0'); + hexDatas.Add(rateNumberHex); + + var intBitNumberBin = (meter.IntegerBitNumber - 4).DecToBin().PadLeft(2, '0'); + var decBitNumberBin = (meter.DecimalBitNumber - 1).DecToBin().PadLeft(2, '0'); + var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}"; + var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0'); + hexDatas.Add(intAndDecBitNumberHex); + + hexDatas.Add(meter.CollectorAddress.PadLeft(12, '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); + } + + //高位在前,低位在后 + var datas = new List(); + foreach (var hexData in hexDatas) + { + if (hexData.Length == 2) + datas.Add(hexData); + else + { + var lst = hexData.StringToPairs(); + lst.Reverse(); + datas.AddRange(lst); + } + } + datas.AddRange(GetPW()); + return datas; + } + + /// + /// 构建水表参数设置-下发数据单元 + /// + /// + /// + private static List BuildWaterMeterParameterSendDataUnit(List meterParameters) + { + var hexDatas = new List(); + + var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0'); + hexDatas.Add(countHex); + + for (int i = 0; i <= meterParameters.Count - 1; i++) + { + + var meter = meterParameters[i]; + var protocolType = (int)meter.ProtocolType; + + var currentProtocolType = protocolType; + if (protocolType == 43) + currentProtocolType = 1; + else if (protocolType > 32) currentProtocolType = 32; + + //TODO:无线水表 小数位 + if (currentProtocolType == 32 && meter.Address.Substring(0, 2) != "00") + { + var ejz = meter.Address.Substring(0, 2).HexToBin().PadLeft(8, '0'); + var xs = ejz.Substring(6, 2).BinToDec(); + var zs = ejz.Substring(0, 6).BinToDec(); + //userData.Add(new QGDW3671UserData() { Name = "整数位无线水表", Value = zs }); + //userData.Add(new QGDW3671UserData() { Name = "小数位无线水表", Value = xs }); + } + + var userCategoryNumber = meter.UserCategoryNumber; + var userSubclassNumber = meter.UserSubclassNumber; + + if (protocolType == 32) + userCategoryNumber = 1; + else if (protocolType == 45) + { + userCategoryNumber = 1; + userSubclassNumber = 9; + } + else if (protocolType == 1) + userSubclassNumber = 1; + + var indexHex = (i + 1).DecToHex().PadLeft(4, '0'); + hexDatas.Add(indexHex); + + var pnHex = meter.Pn.DecToHex().PadLeft(4, '0'); + hexDatas.Add(pnHex); + + var baudRateBin = meter.BaudRate.DecToBin().PadLeft(3, '0'); + var portBin = meter.Port.DecToBin().PadLeft(5, '0'); + var baudRateAndPortHex = $"{baudRateBin}{portBin}".BinToHex().PadLeft(2, '0'); + hexDatas.Add(baudRateAndPortHex); + + var protocolTypeHex = currentProtocolType.DecToHex().PadLeft(2, '0'); + hexDatas.Add(protocolTypeHex); + + hexDatas.Add(meter.Address); + + hexDatas.Add(meter.Password.PadLeft(12, '0')); + + var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}"; + var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0'); + hexDatas.Add(rateNumberHex); + + var intBitNumberBin = meter.IntegerBitNumber.DecToBin().PadLeft(2, '0'); + var decBitNumberBin = meter.DecimalBitNumber.DecToBin().PadLeft(2, '0'); + var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}"; + var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0'); + hexDatas.Add(intAndDecBitNumberHex); + + hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0')); + + 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); + } + + //高位在前,低位在后 + var datas = new List(); + foreach (var hexData in hexDatas) + { + if (hexData.Length == 2) + datas.Add(hexData); + else + { + var lst = hexData.StringToPairs(); + lst.Reverse(); + datas.AddRange(lst); + } + } + datas.AddRange(GetPW()); + return datas; + } + + + //AUX=消息认证码字段(PW,16个字节) + private static List GetPW() + { + var str = "00"; + var pWList = Enumerable.Repeat(str, pWLen).ToList(); + return pWList; + } + + + /// + /// 帧校验和 + /// + /// 用户数据区 + /// + private static string GetCS(List userData) + { + byte sum = 0; + foreach (var d in userData) + { + var b = Convert.ToByte(d, 16); + sum += b; + } + return sum.ToString("X2"); + } + + /// + /// 用户数据区 + /// + /// + /// + private static List BuildUserData(ReqParameter reqParameter, List? dataUnit) + { + var c = BuildC(reqParameter.FunCode, reqParameter.PRM); + var a = BuildAList(reqParameter.A, reqParameter.MSA); + + var linkUserData = BuildLinkUserData(reqParameter.AFN, reqParameter.Seq, + ((ReqParameter2)reqParameter).Pn, ((ReqParameter2)reqParameter).Fn, dataUnit); + + var list = new List() { c }; + list.AddRange(a); + list.AddRange(linkUserData); + return list; + } + + /// + /// 固定长度的报文头 起始字符+长度+长度+起始字符 + /// + /// + /// + private static List BuildHeaders(int length) + { + var headers = new List(); + headers.Add(startStr); + var l = BuildLength(length); + headers.AddRange(l); + headers.AddRange(l); + headers.Add(startStr); + return headers; + } + + /// + /// 长度 2字节 [用户数据区长度] + /// + /// + private static List BuildLength(int length1) + { + var binaryLen = length1.DecToBin(); + var protocolIdentification = Enum.Format(typeof(ProtocolIdentification), + ProtocolIdentification.本规约使用, "d").PadLeft(2, '0'); + var lenStr = $"{binaryLen}{protocolIdentification}"; + var hexLen = lenStr.BinToHex(); + hexLen = hexLen.PadLeft(4, '0'); + var list = hexLen.StringToPairs(); + list.Reverse(); + return list; + } + + /// + /// 控制域 + /// + /// 功能码 + /// + /// + /// + private static string BuildC(int funCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效) + { + var cMasterStationFunCodeHex = funCode.DecToBin(); + cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0'); + var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}"; + var hexC = strC.BinToHex().PadLeft(2, '0'); + return hexC; + } + + + /// + /// 地址域 3220 09872 + /// + /// 行政区划码 BCD码 3220=2032 + /// 逻辑地址 BIN 09872=2690=>9026 + /// 主站地址 BIN 0~127 + /// + private static List BuildAList(string a, int mSA) + { + var list = new List(); + + var a1 = a.Substring(0, 4); + var a1Pairs = a1.StringToPairs(); + a1Pairs.Reverse(); + list.AddRange(a1Pairs); + + var a2 = Convert.ToInt32(a.Substring(4)); + var decA2 = a2.DecToHex(); + var a2Pairs = decA2.PadLeft(4, '0').StringToPairs(); + a2Pairs.Reverse(); + list.AddRange(a2Pairs); + + //TODO:主站地址和组地址标志 + var a3Bin = $"{mSA.DecToBin().PadLeft(7, '0')}0"; + list.Add(a3Bin.BinToHex().PadLeft(2, '0')); + + return list; + } + + private static List BuildLinkUserData(AFN aFN, Seq seq, int pn, int fn, List? dataUnit) + { + var aFNValue = ((int)aFN).DecToHex().PadLeft(2, '0'); + var sEQ = BuildSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ); + var dA = BuildDA(pn); + var dT = BuildDT(fn); + var list = new List() { aFNValue, sEQ }; + list.AddRange(dA); + list.AddRange(dT); + + if (dataUnit != null) + { + list.AddRange(dataUnit); + } + //list.AddRange(GetDataUnit(aFN,seq)); + + if (seq.TpV == TpV.附加信息域中带时间标签) + list.AddRange(BuildTp("00")); + + return list; + } + + /// + /// 帧序列域 + /// + /// + /// + /// + /// + private static string BuildSEQ(TpV tpV, FIRFIN fIRFIN, CON cON, int pRSEQ) + { + var tpVValue = Enum.Format(typeof(TpV), + tpV, "d"); + var fIRFINValue = Enum.Format(typeof(FIRFIN), + fIRFIN, "d"); + var cONValue = (int)cON; + var sEQBin = $"{tpVValue}{fIRFINValue}{cONValue}{pRSEQ.DecToBin().PadLeft(4, '0')}"; + var hexSEQ = sEQBin.BinToHex().PadLeft(2, '0'); + return hexSEQ; + } + + /// + /// 信息点标识 + /// + /// 计量点 + /// + private static List BuildDA(int pn) + { + if (pn == 0) + return new List() { "00", "00" }; + var dA2 = (pn - 1) / 8 + 1;//信息点组从1开始 第几组 + var dA1 = pn - (dA2 - 1) * 8;//pn % 8 + var dA1Hex = "1".PadRight(dA1, '0').BinToHex();//对位信息 第几位 二进制有效位 + var dA2Hex = dA2.DecToHex(); + return new List() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') }; + + } + + /// + /// 数据单元标识 + /// + /// + /// + private static List BuildDT(int fn) + { + var dT2 = (fn - 1) / 8;//从零开始 第几组 + var dT1 = fn - dT2 * 8; + var dT1Hex = "1".PadRight(dT1, '0').BinToHex();//对位信息 第几位 二进制有效位 + var dT2Hex = dT2.DecToHex(); + return new List() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') }; + } + + /// + /// 时间标签 + /// + /// 启动帧帧序号计数器PFC 1字节 + /// 允许发送传输延时时间 min 1字节 + /// + private static List BuildTp(string pFC = "00", int delayTime = 0) + { + var now = DateTime.Now; // 获取当前时间 + var seconds = now.Second.ToString().PadLeft(2, '0'); // 获取当前秒数 + var minutes = now.Minute.ToString().PadLeft(2, '0'); // 获取当前分钟数 + var hours = now.Hour.ToString().PadLeft(2, '0'); // 获取当前小时数 + var day = now.Day.ToString().PadLeft(2, '0'); // 获取当前日期的日数 + return new List() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') }; + } + + #endregion + + } +} diff --git a/src/JiShe.CollectBus.Common/BuildSendDatas/Build645SendData.cs b/src/JiShe.CollectBus.Common/BuildSendDatas/Build645SendData.cs new file mode 100644 index 0000000..d3df6cb --- /dev/null +++ b/src/JiShe.CollectBus.Common/BuildSendDatas/Build645SendData.cs @@ -0,0 +1,755 @@ +using JiShe.CollectBus.Common.Enums; +using JiShe.CollectBus.Common.Extensions; +using JiShe.CollectBus.Common.Models; +using System; +using System.Collections.Generic; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace JiShe.CollectBus.Common.BuildSendDatas +{ + public static class Build645SendData + { + //起始字符 + private const string startStr = "68"; + //结束字符 + private const string endStr = "16"; + + #region 645下行命令 + + + /// + /// 构建电表阀控下发数据单元 + /// + /// 电表地址 + /// 特殊控制码 + /// 密码 + /// 是否为开阀 + /// 型号码 + /// + public static List BuildAmmeterValveControlSendDataUnit(string ammeterAddress, string specialControlCode, string password, bool state, string modelCode = "") + { + var code = string.Empty; + + if (state) + { + if (string.IsNullOrEmpty(specialControlCode)) + code = "1B"; + else + code = specialControlCode == "1B" || specialControlCode == "1C" ? specialControlCode : "1C"; + } + else + code = "1A";//跳闸 + + if (specialControlCode == "1W") + { + if (state) + code = "1A"; + else + code = "1C"; + } + + var pwdLevel = "02"; + if (modelCode == "HL_DTSU2625" || modelCode == "DDZY9866") + pwdLevel = "04"; + else if (modelCode == "DDS2705") + pwdLevel = "03"; //不带安全认证密级 + + if (!string.IsNullOrWhiteSpace(password) && password.Contains("|")) + { + var sp = password.Split('|'); + pwdLevel = sp[1]; + password = sp[0]; + } + + var strDate = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan();//命令有效截止时间 + if (specialControlCode == "1D" || modelCode == "SZBD_DDZY1225") + strDate = "FF FF FF FF FF FF"; + var strP = password.StrAddSpan().StrReverseOrder(); + var strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + code + " 00 " + strDate; + var dataUnit = strSJY.Replace(" ", "").StringToPairs(); + var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit); + return dataList; + + //string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2"); + //string strReturn = "68 " + address.StrAddSpan().StrReverseOrder() + " 68 1C " + strLen + " " + strSJY.StrAddHex33() + " "; + //string strSum = strReturn.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); + //strReturn += strSum.Substring(strSum.Length - 2) + " 16"; + //return strReturn.Split(' ').ToList(); + } + + /// + /// 构建电表保电下发数据单元 + /// + /// 电表地址 + /// + /// true 保电 false 保电解除 + /// 型号码 + /// + public static List BuildAmmeterLockSendDataUnit(string ammeterAddress, string password, bool state, string modelCode = "") + { + var code = state ? "3A" : "3B"; + + var strDate = (code + DateTime.Now.AddDays(1).ToString("00000012ddMMyy")).StrAddSpan(); + + if (modelCode == "SZBD_DDZY1225") + strDate = $"{code} 00 FF FF FF FF FF FF"; + + var strP = password.StrAddSpan().StrReverseOrder(); + var strSJY = " 02 " + strP + " 01 00 00 00 " + strDate; + + var dataUnit = strSJY.Replace(" ", "").StringToPairs(); + var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit); + return dataList; + } + + /// + /// 构建电表认证下发数据单元 + /// + /// 电表地址 + /// + /// + /// + public static List BuildAmmeterIdentitySendDataUnit(string ammeterAddress, string ramDon, string maco) + { + var codeList = "070004FF".StringToPairs(); + codeList.Reverse(); + + var ramDonList = ramDon.StringToPairs(); + ramDonList.Reverse(); + + var macoList = maco.StringToPairs(); + macoList.Reverse(); + + var dataUnit = new List(); + dataUnit.AddRange(codeList); + dataUnit.AddRange(ramDonList); + dataUnit.AddRange(macoList); + var dataList = Build645SendCommand(ammeterAddress, "03", dataUnit); + return dataList; + } + + /// + /// 构建电表清零下发数据单元 + /// + /// 电表地址 + /// + /// + 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(ammeterAddress, "1A", dataUnit); + return dataList; + } + + /// + /// 透明转发 表计校时/广播校时 F10-104 + /// + /// + /// + /// + /// + /// 类型 0:日期部分指令,1,时间部分指令 + /// + /// + /// + public static List BuildAmmeterCorrectionTimeSendDataUnit(string ammeterAddress,string password, string dataMark, int cmdType, string s_operator = "00000001") + { + List dataUnit = new List(); + + if (string.IsNullOrWhiteSpace(password)) + password = "000000"; + if (password?.Length != 6) + password = password.PadLeft(6, '0'); + if (string.IsNullOrWhiteSpace(s_operator) || s_operator?.Length != 8) + throw new ArgumentNullException("电表操作人员格式不能为空或长度不等6位"); + + //数据标识 DIODI1DI2DI3+PAP0P1P2+C0C1C2C3+DATA + var dataMarks = dataMark.Split(' ').ToList(); + dataMarks.Reverse(); + dataUnit.AddRange(dataMarks);//数据标识 + + //密码权限 02明文 PAP0P1P2 + var passsList = password.StringToPairs(true); + dataUnit.Add("02");//--密码权限 02明文 + foreach (var item in passsList) + { + dataUnit.Add(item); + } + //操作人员 C0C1C2C3 + var opers = s_operator.StringToPairs(true); + foreach (var item in opers) + { + dataUnit.Add(item); + } + //数据体 DATA + List datas = null; + switch (cmdType) + { + case 0: + datas = Date_MeterTiming(); + break; + case 1: + datas = Time_MeterTiming(); + break; + } + if (datas == null) + throw new Exception($"透明转发 表计校时/广播校时生成的数据内容为空"); + datas.Reverse(); + dataUnit.AddRange(datas); + + var dataList = Build645SendCommand(ammeterAddress, "14", dataUnit); + return dataList; + } + + /// + /// 设置尖峰平谷时段 F10-103 + /// + /// + /// + /// + /// + /// + /// + /// + public static List BuildAmmeterTimeSetSendDataUnit(string ammeterAddress,string password, string dataMark,string data, string s_operator= "00000001") + { + List dataUnit = BuildAmmeterTimeSetDataUnit(password, dataMark, data); + + var dataList = Build645SendCommand(ammeterAddress, "14", dataUnit); + return dataList; + } + //工具生成指令 F10 103 + //internal override List GenerateContent(SetJFPGToolCmdIssueEntity transpond) + //{ + // //TODO:替换表计地址 + // var meterAddress = string.Join("", transpond.MeterAddress.Split(2, true)).PadRight(12, '0').Split(2, false); + // var cmdArr = transpond.Cmd.Replace(" ", "").Split(2, false); + // cmdArr.RemoveRange(1, 6); + // cmdArr.InsertRange(1, meterAddress); + // //TODO:替换校验码 + // var csSum = GetCheckSumsHexString(string.Join("", cmdArr.Take(cmdArr.Count - 2)).StringToHexByte()); + // cmdArr.RemoveRange(cmdArr.Count - 2, 2); + // cmdArr.Add(csSum); + + // cmdArr.Add("16"); + + // return cmdArr; + //} + + public static List BuildAmmeterGenerateBCCommand() + { + return null; + } + + + /// + /// 构建电表读取下发数据单元 + /// + /// 电表地址 + /// 功率读取 余额读取 + /// 数据标识 + /// + 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; + } + + /// + /// 构建电表修正时间下发命令-PMAC9523 + /// + /// + /// + public static List BuildPMAC9523AmmeterCorrectionTimeSendDataUnit(string ammeterAddress) + { + 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 = HexStringExtensions.GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2, '0'));//long.Parse ? + fm.AddRange(getCrc); + + return fm; + } + + /// + /// 构建电表修正时间下发命令-DTSU193 + /// + /// + /// + public static List BuildDTSU193AmmeterCorrectionTimeSendDataUnit(string ammeterAddress) + { + 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}"); + return fm; + } + + /// + /// 构建电表修正时间下发命令 + /// + /// + /// + /// + public static List> BuildAmmeterCorrectionTimeSendDataUnit(string ammeterAddress,string password) + { + var listDataUnit = new List>(); + + 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); + listDataUnit.Add(fm); + + 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)); + var fm2 = Build645SendCommand(ammeterAddress, "14", dataList); + listDataUnit.Add(fm2); + + return listDataUnit; + } + + /// + /// + /// + /// + /// + public static List BuildPMAC9523ReadMeterTimeSetSendDataUnit(string ammeterAddress) + { + //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 = HexStringExtensions.GetCRC16(bts, true) + .Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2, '0')); + fm.AddRange(getCrc); + return fm; + + } + + /// + /// 构建电表表号读取下发命令 + /// + /// 电表地址 + /// + public static List BuildAmmeterReadNumSendCmd(string ammeterAddress) + { + var dataUnit = "04000402".StringToPairs(true); + return Build645SendCommand(ammeterAddress, "11", dataUnit); + } + + public static List> BuildPMAC9523AmmeterSetTimeSetSendDataUnit(string ammeterAddress, List data) + { + List> dataUnitList = new List>(); + 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 = HexStringExtensions.GetCRC16(bts, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2, '0')); + fm.AddRange(getCrc); + dataUnitList.Add(fm); + + //第二步写复费率模式:寄存器22002,写数据01固定一套费率 + var fm2 = new List() { adress, "10", "55", "F1", "00", "01", "02", "00", "01" }; + var bts2 = fm2.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray(); + var getCrc2 = HexStringExtensions.GetCRC16(bts2, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2, '0')); + fm2.AddRange(getCrc2); + dataUnitList.Add(fm2); + + //第三步写时段参数:寄存器22010开始,后续多少个寄存器根据时段内容来。 + var timeSetDetailList = data.FirstOrDefault().Data; + var fm3 = new List() { adress, "10", "55", "F9", "00" }; + //寄存器个数 + var timeNum = timeSetDetailList.Sum(o => o.Times.Count); + fm3.Add($"{timeNum * 2 + 1:X2}"); + //数据长度 + fm3.Add($"{(timeNum * 2 + 1) * 2:X2}"); + + //时段个数 + fm3.Add("00"); + fm3.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) + { + fm3.Add("00"); + fm3.Add($"{rate - 1:X2}"); + fm3.Add("00"); + fm3.Add($"{itemItem.StartTime.TakeTimeToInt():X2}"); + } + } + var bts3 = fm3.Select(s => s.HexToDec()).Select(s => byte.Parse(s.ToString())).ToArray(); + var getCrc3 = HexStringExtensions.GetCRC16(bts3, true).Select(s => int.Parse(s.ToString()).DecToHex().PadLeft(2, '0')); + fm3.AddRange(getCrc3); + dataUnitList.Add(fm3); + + return dataUnitList; + } + + /// + /// F1:透明转发 读取通信地址 04 00 04 01 NNNNNNNNNNNN 6 通信地址 + /// + /// + /// + public static List BuildReadMeterAddressSendDataUnit(string ammeterAddress) + { + var dataMark = new List { "04", "00", "04", "01" }; + //content.AddRange(string.Join("", transpond.MeterAddress.Split(2, true)).PadRight(12, '0').Split(2, false)); + dataMark.Reverse(); + return Build645SendCommand(ammeterAddress, "11", dataMark); + } + + /// + /// 构建645协议下发命令 + /// + /// 电表地址 + /// 控制码 + /// 数据域 发送方按字节进行加33处理,接收方按字节减33 + /// + public static List Build645SendCommand(string ammeterAddress, string controlCode, List? dataUnit) + { + var cmdStrList = new List(); + cmdStrList.Add(startStr); + + ammeterAddress = ammeterAddress.PadLeft(12, '0'); + var addressList = ammeterAddress.StringToPairs(); + addressList.Reverse(); + cmdStrList.AddRange(addressList); + + cmdStrList.Add(startStr); + + cmdStrList.Add(controlCode); + + var len = dataUnit != null ? dataUnit.Count.DecToHex().PadLeft(2, '0') : "00"; + cmdStrList.Add(len); + + if (dataUnit != null) + { + cmdStrList.AddRange(dataUnit.AddHex33()); + } + + var strSum = cmdStrList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); + strSum = strSum.Substring(strSum.Length - 2); + cmdStrList.Add(strSum); + cmdStrList.Add(endStr); + + return cmdStrList; + } + + /// + /// 威胜表的超功率(第一路恶性负载超功率判断阀值) + /// + /// + /// + /// + /// + /// + 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(ammeterAddress, password, dataMark, data); + } + /// + /// 威胜表的超功率(超功率开关) + /// + /// + /// + /// + /// + public static List AssembleWsOnSupperPower(string ammeterAddress, string password, bool isOn = true) + { + var data = new string[] { (isOn ? "01" : "00") }; + return AssembleWrite(ammeterAddress, password, "0E400001", data); + } + /// + /// 威胜表的超功率(第一路恶性负载绝对功率判断阈值) + /// + /// + /// + /// + /// + /// + 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(ammeterAddress, password, dataMark, data); + } + /// + /// 威胜表的超功率(第一路恶性负载功率因数判断阀值) + /// + /// + /// + /// + /// + /// + 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(ammeterAddress, password, dataMark, data); + } + + /// + /// 构建写数据 + /// + /// + /// + /// + /// + /// + public static List AssembleWrite(string ammeterAddress, string password, string di0_3, string[] data) + { + var returnList = new List(); + returnList.Add(startStr); + + var addressList = ammeterAddress.StringToPairs(); + addressList.Reverse(); + returnList.AddRange(addressList); + + returnList.Add(startStr); + returnList.Add("14"); + + var len = (12 + data.Length).ToString("X2"); + returnList.Add(len); + + + var di03List = di0_3.StringToPairs(); + di03List.Reverse(); + di03List.Add("02"); + + var pwdList = password.StringToPairs(); + pwdList.Reverse(); + di03List.AddRange(pwdList); + + var mList = new List() { "00", "11", "22", "33" }; + di03List.AddRange(mList); + di03List.AddRange(data); + var listAdd33 = di03List.AddHex33(); + + returnList.AddRange(listAdd33); + + var strSum = returnList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); + var cs = strSum.Substring(strSum.Length - 2); + returnList.Add(cs); + returnList.Add(endStr); + + return returnList; + } + + /// + /// 生成软编程指令 + /// 型号编码 + /// + /// + public static List SoftProgram(string ammeterAddress, string modelCode, string password) + { + string bccmd = string.Empty; + if (modelCode == "DDS71") + { + + bccmd = "68 AA AA AA AA AA AA 68 04 07 4E F4 35 BB BB BB 32"; + } + else + { + bccmd = "68 AA AA AA AA AA AA 68 14 10 41 35 33 41 37 33 33 33 34 33 33 33 77 66 55 44"; + } + + //替换密码 + var passwordList = password.StringToPairs(); + passwordList.Reverse(); + passwordList = passwordList.AddHex33(); + var passwordStr = string.Join(" ", passwordList); + bccmd = bccmd.Replace("BB BB BB", passwordStr); + //替换表地址 + var addressList = ammeterAddress.StringToPairs(); + addressList.Reverse(); + var addressStr = string.Join(" ", addressList); + bccmd = bccmd.Replace("AA AA AA AA AA AA", addressStr); + var fm = bccmd.Split(' ').ToList(); + //生成CRC + var cRC = HexStringExtensions.GetCRC(fm); + fm.Add(cRC); + fm.Add("16"); + + 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 = HexStringExtensions.GetCRC(fm); + fm.Add(cRC); + fm.Add(endStr); + return fm; + } + + private static List Time_MeterTiming() + { + return new List + { + DateTime.Now.Hour.ToString().PadLeft(2, '0'), + DateTime.Now.Minute.ToString().PadLeft(2, '0'), + (DateTime.Now.Second + 2).ToString().PadLeft(2, '0') + }; + } + + private static List Date_MeterTiming() + { + var week = (int)DateTime.Now.DayOfWeek; + var year = DateTime.Now.Year; + var month = DateTime.Now.Month; + var day = DateTime.Now.Day; + + return new List + { + year.ToString().Substring(2,2).PadLeft(2,'0'), + month.ToString().PadLeft(2,'0'), + day.ToString().PadLeft(2,'0'), + week.ToString().PadLeft(2,'0'), + }; + } + + /// + /// 构建电表时段设置数据单元 + /// + /// + /// + /// + /// + /// + /// + /// + private static List BuildAmmeterTimeSetDataUnit(string password, string dataMark, string data, string s_operator = "00000001") + { + List dataUnit = new List(); + if (string.IsNullOrWhiteSpace(password)) + password = "000000"; + if (password?.Length != 6) + password = password.PadLeft(6, '0'); + if (string.IsNullOrWhiteSpace(s_operator) || s_operator?.Length != 8) + throw new ArgumentNullException("电表操作人员格式不能为空或长度不等6位"); + + //数据标识 DIODI1DI2DI3+PAP0P1P2+C0C1C2C3+DATA + var dataMarks = dataMark.Split(' ').ToList(); + dataMarks.Reverse(); + dataUnit.AddRange(dataMarks);//数据标识 + + //密码权限 02明文 PAP0P1P2 + var passs = password.StringToPairs(true); + dataUnit.Add("02");//--密码权限 02明文 + foreach (var item in passs) + { + dataUnit.Add(item); + } + //操作人员 C0C1C2C3 + var opers = s_operator.StringToPairs(true); + foreach (var item in opers) + { + dataUnit.Add(item); + } + //TODO:数据体 DATA + var datas = data.Split(' ').ToList(); + datas.Reverse(); + dataUnit.AddRange(datas); + return dataUnit; + } + + #endregion + } +} diff --git a/src/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs b/src/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs index 8d034fa..20ee829 100644 --- a/src/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs +++ b/src/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs @@ -1,11 +1,6 @@ using System.ComponentModel.DataAnnotations; 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 { @@ -20,44 +15,9 @@ namespace JiShe.CollectBus.Common.Extensions //消息认证码字段长度 private const int pWLen = 16; - private const int tPLen = 6; - private const int FixedLength = 18; - static object locker = new object(); - static List MSA = new List(); - static Dictionary> usingMSA = new Dictionary>(); - - static HexStringExtensions() - { - for (int i = 1; i <= 127; i++) - { - MSA.Add(i); - } - } - /// - /// Gets the msa. - /// - /// 集中器地址 - /// - public static int GetMSA(string mark) - { - lock (locker) - { - if (!usingMSA.Keys.Contains(mark)) - usingMSA.Add(mark, new List()); - - int msa = MSA.Except(usingMSA[mark]).FirstOrDefault(); - //if (msa == 1) msa = 2;//msa=1为自定义指令保留 - usingMSA[mark].Add(msa); - - if (msa == 127) - usingMSA[mark].RemoveAll(m => true); - - return msa; - } - } - + public static object GetAnalyzeValue(this List hexStringList, CommandChunkEnum chunk) { if (hexStringList.Count < hearderLen || hexStringList[0] != startStr || hexStringList[5] != startStr || hexStringList.Count < FixedLength) @@ -140,2132 +100,15 @@ namespace JiShe.CollectBus.Common.Extensions return hexStringList; } - #region 376.1下行命令 - - /// - /// 构建电表参数设置-下发命令 - /// - /// 集中器地址 - /// - /// - public static byte[] BuildAmmeterParameterSetSendCmd(string address, List meterParameters) + public static List ReduceHex33(this List hexStringList) { - var dataUnit = BuildAmmeterParameterSendDataUnit(meterParameters); - var reqParameter = new ReqParameter2() + for (int i = 0; i < hexStringList.Count; i++) { - 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 = 10 - }; - var bytes = BuildSendCommandBytes(reqParameter, dataUnit); - return bytes; - } - - /// - /// 构建电表参数读取-下发命令 - /// - /// 集中器地址 - /// 对象序号 - public static byte[] BuildAmmeterParameterReadingSendCmd(string address, List meterNumberList) - { - var dataUnit = new List(); - var countHex = meterNumberList.Count().DecToHex().PadLeft(4, '0'); - var countHexPairs = countHex.StringToPairs(); - countHexPairs.Reverse(); - dataUnit.AddRange(countHexPairs); - - foreach (var number in meterNumberList) - { - var numberHex = number.DecToHex().PadLeft(4, '0'); - var numberHexPairs = numberHex.StringToPairs(); - numberHexPairs.Reverse(); - dataUnit.AddRange(numberHexPairs); + var value = Convert.ToInt32(hexStringList[i], 16) - Convert.ToInt32("33", 16); + hexStringList[i] = value.DecToHex().PadLeft(2, '0'); } - var reqParameter = new ReqParameter2() - { - AFN = AFN.查询参数, - FunCode = (int)CMasterStationFunCode.请求2级数据, - A = address, - Seq = new Seq() - { - TpV = TpV.附加信息域中无时间标签, - FIRFIN = FIRFIN.单帧, - CON = CON.不需要对该帧进行确认, - PRSEQ = 0, - }, - MSA = GetMSA(address), - Pn = 0, - Fn = 10 - }; - var bytes = BuildSendCommandBytes(reqParameter, dataUnit); - return bytes; - } - - /// - /// 构建电表抄读一类数据-下发命令 - /// - /// - /// - /// 一类数据项 - public static byte[] BuildAmmeterReadRealTimeDataSendCmd(string address, int pn, ATypeOfDataItems aTypeOfDataItems) - { - 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 = pn, - Fn = (int)aTypeOfDataItems - }; - var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter); - return bytes; - } - - /// - /// 构建电表抄读日冻结正向有功电能示值-下发命令 - /// - /// - /// - /// - public static void BuildAmmeterReadDailyFreezingDataSendCmd(string address, int pn, DateTime time) - { - var dataUnit = time.ToString("yy-MM-dd").Split('-').ToList(); - dataUnit.Reverse(); - 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 = pn, - Fn = 161 - }; - var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter, dataUnit); - } - - /// - /// 构建电表抄读实时电流-下发命令 - /// - /// - /// - public static void BuildAmmeterRealTimeCurrentDataSendCmd(string address, int pn) - { - 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 = pn, - Fn = 25 - }; - var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter); - } - - - /// - /// 构建电表读取二类数据-下发命令 - /// - /// - /// - /// fn - /// 冻结密度 - /// 冻结点数 - /// 起始时间 - public static byte[] BuildAmmeterReadingIIdataTypeItemsSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems, FreezeDensity density,int points,DateTime? beginTime = null) - { - var queryDate = beginTime ?? DateTime.Today.AddDays(-1); - var dataUnit = queryDate.ToString("yyMMddHHmm").StringToPairs(); - dataUnit.Reverse(); - - //冻结密度 - dataUnit.Add(((int)density).DecToHex()); - - dataUnit.Add(points.DecToHex()); - - 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 = pn, - Fn = (int)iIDataTypeItems - }; - var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter, dataUnit); - return bytes; - } - - /// - /// 构建电表读取二类数据-下发命令 - /// - /// - /// - /// fn - /// 数据时标 - /// 起始时间 - public static void BuildAmmeterReadingBaseDataSendCmd(string address, int pn, IIdataTypeItems iIDataTypeItems,TdType tdType, DateTime? beginTime = null) - { - var queryDate = beginTime ?? DateTime.Today.AddDays(-1); - List? dataUnit = null; - switch (tdType) - { - case TdType.Td_d: - dataUnit = queryDate.ToString("yyMMdd").StringToPairs(); - break; - case TdType.Td_m: - dataUnit = queryDate.ToString("yyMM").StringToPairs(); - break; - } - - if(dataUnit == null) return; - - dataUnit.Reverse(); - 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 = pn, - Fn = (int)iIDataTypeItems - }; - var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter, dataUnit); - } - - - /// - /// 组装有/无功电量 - /// - /// - /// - /// - public static void BuildAmmeterReadingElectricityDataSendCmd(string address, int pn,int cmdType) - { - 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 = pn, - Fn = cmdType - }; - var bytes = HexStringExtensions.BuildSendCommandBytes(reqParameter); - } - - /// - /// 构建超功率设置-下发命令 - /// - /// - /// - /// - /// - /// - /// - public static void BuildAmmeterSuperpowerSettingSendCmd(string address, string password,string modelCode, int port, string baudRate, decimal power) - { - if (power > 0) - { - - WsOnSupperPower(address, password, modelCode, true, port, baudRate); - - //TODO:连续发几条嘛? - string dataMark; - //如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001 - if (address.IndexOf('_') > 0) - { - var addressSplit = address.Split('_'); - address = addressSplit[0]; - var loop = Convert.ToInt32(addressSplit[1]); - if (loop == 1) { dataMark = "0E300101"; } - else if (loop == 2) { dataMark = "0E300201"; } - else - return; - } - else - { - dataMark = "0E300101"; - } - - var turnData = AssembleWsSupperPower(address, password, dataMark, power); - if (turnData != null) - { - var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData); - } - } - else - { - WsOnSupperPower(address, password, modelCode, false, port, baudRate); - } - - } - - /// - /// 构建恶性负载绝对功率设置-下发命令 - /// - /// - /// - /// - /// - /// - public static void BuildAmmeterAbsolutePowerSettingSendCmd(string address, string password, int port, string baudRate, decimal power) - { - if (power <= 0) - { - power = 99;//等于小0 代表关闭 - } - - string dataMark; - //如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001 - if (address.IndexOf('_') > 0) - { - var addressSplit = address.Split('_'); - address = addressSplit[0]; - - var loop = Convert.ToInt32(addressSplit[1]); - if (loop == 1) { dataMark = "0E300103"; } - else if (loop == 2) { dataMark = "0E300203"; } - else - return; - } - else - { - dataMark = "0E300103"; - } - - var turnData = AssembleWsAbsolutePowerSetting(address, password, dataMark, power); - if (turnData != null) - { - var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData); - } - } - - /// - /// 构建恶性负载功率因数设置-下发命令 - /// - /// - /// - /// - /// - /// - public static void BuildAmmeterPowerFactorSettingSendCmd(string address, string password, int port, string baudRate, decimal power) - { - string dataMark; - //如果是多回路电表,地址只取前面部分 例如:564880000001_01 取564880000001 - if (address.IndexOf('_') > 0) - { - var addressSplit = address.Split('_'); - address = addressSplit[0]; - - var loop = Convert.ToInt32(addressSplit[1]); - if (loop == 1) { dataMark = "0E300104"; } - else if (loop == 2) { dataMark = "0E300204"; } - else - return; - } - else - { - dataMark = "0E300104"; - } - - var turnData = AssembleWsPowerFactor(address, password, dataMark, power); - if (turnData != null) - { - var bytes = BuildTransparentForwardingSendCmd(address, port, baudRate, turnData); - } - } - - /// - /// 超功率开关 - /// - /// - /// - /// - /// - /// - 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" }; - //这些型号需进入软编程 - if (modelCodes.Contains(modelCode)) - { - var dataUnit1 = SoftProgram(address, modelCode, password); - BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit1); - } - - var dataUnit2 = AssembleWsOnSupperPower(address, password, isOn); - BuildTransparentForwardingSendCmd(address, port, baudRate, dataUnit2); - } - - - /// - /// 构建水表参数设置-下发命令 - /// - /// 集中器地址 - /// - /// - public static byte[] BuildWaterMeterParameterSetSendCmd(string address, List meterParameters) - { - var dataUnit = BuildWaterMeterParameterSendDataUnit(meterParameters); - 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 = 10 - }; - var bytes = BuildSendCommandBytes(reqParameter, dataUnit); - 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 - /// 300,600,1200,2400,4800,7200,9600,19200对应 0~7 - /// 转发内容 - /// 停止位 - /// 校验方式 - /// 数据位 - /// 等待报文超时时间/s - /// 等待字节超时时间/ms - 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 baudRateValue = GetBaudreate(baudRate); - - var dataUnit = BuildTransparentForwardingSendDataUnit(port, baudRateValue, datas, stopBit, parity, dataBit, waitContentTimeout, waitByteTimeout); - dataUnit.AddRange(GetPW()); - var reqParameter = new ReqParameter2() - { - AFN = AFN.数据转发, - FunCode = (int)CMasterStationFunCode.请求2级数据, - A = address, - Seq = new Seq() - { - TpV = TpV.附加信息域中无时间标签, - FIRFIN = FIRFIN.单帧, - CON = CON.不需要对该帧进行确认, - PRSEQ = 0 - }, - MSA = GetMSA(address), - Pn = 0, - Fn = 1 - }; - var bytes = BuildSendCommandBytes(reqParameter, dataUnit); - 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 = "") - { - address = address.Trim().TrimStart('0'); - if (address.Length < 12) address = address.PadLeft(12, '0'); - string Code = string.Empty; - - if (state) - { - if (string.IsNullOrEmpty(specialnocode)) - Code = "1B"; - else - Code = specialnocode == "1B" || specialnocode == "1C" ? specialnocode : "1C"; - } - else - Code = "1A";//跳闸 - - if (specialnocode == "1W") - { - if (state) - Code = "1A"; - else - Code = "1C"; - } - - var pwdLevel = "02"; - if (modelCode == "HL_DTSU2625" || modelCode == "DDZY9866") - pwdLevel = "04"; - else if (modelCode == "DDS2705") - pwdLevel = "03"; - - if (!string.IsNullOrWhiteSpace(password) && password.Contains("|")) - { - var sp = password.Split('|'); - pwdLevel = sp[1]; - password = sp[0]; - } - - string strDate = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan(); - if (specialnocode == "1D" || modelCode == "SZBD_DDZY1225") - strDate = "FF FF FF FF FF FF"; - string strP = password.StrAddSpan().StrReverseOrder(); - string strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + Code + " 00 " + strDate; - string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2"); - string strReturn = "68 " + address.StrAddSpan().StrReverseOrder() + " 68 1C " + strLen + " " + strSJY.StrAddHex33() + " "; - string strSum = strReturn.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); - strReturn += strSum.Substring(strSum.Length - 2) + " 16"; - - return strReturn.Split(' ').ToList(); - } - - - /// - /// 构建透明转发-下发数据单元 - /// - /// 终端通信端口 1~31 - /// 0~7 对应300,600,1200,2400,4800,7200,9600,19200 - /// 转发内容 - /// 停止位 - /// 校验方式 - /// 数据位 - /// 等待报文超时时间/s - /// 等待字节超时时间/ms - /// - 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(); - - var portHex = port.DecToHex().PadLeft(2, '0'); - dataUnit.Add(portHex); - - 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'); - var controlHex = $"{baudRateBin}{stopBitBin}{parityBin}{dataBitBin}".BinToHex().PadLeft(2, '0'); ; - dataUnit.Add(controlHex); - - var waitContentTimeoutBin = $"1{waitContentTimeout.DecToBin().PadLeft(7, '0')}"; - var waitContentTimeoutHex = waitContentTimeoutBin.BinToHex().PadLeft(2, '0'); - var waitByteTimeoutHex = waitByteTimeout.DecToHex().PadLeft(2, '0'); - - dataUnit.Add(waitContentTimeoutHex); - dataUnit.Add(waitByteTimeoutHex); - - var countHex = datas.Count.DecToHex().PadLeft(4, '0'); - var countHexPairs = countHex.StringToPairs(); - countHexPairs.Reverse(); - dataUnit.AddRange(countHexPairs); - - dataUnit.AddRange(datas); - - return dataUnit; - } - - /// - /// 构建下发命令 - /// - /// - /// - /// - public static byte[] BuildSendCommandBytes(ReqParameter reqParameter, List? dataUnit = null) - { - var cmdStrList = new List(); - var userDatas = BuildUserData(reqParameter, dataUnit); - var hearders = BuildHeaders(userDatas.Count); - var cs = GetCS(userDatas); - cmdStrList.AddRange(hearders); - cmdStrList.AddRange(userDatas); - cmdStrList.Add(cs); - cmdStrList.Add(endStr); - Console.WriteLine(string.Join(" ", cmdStrList)); - var bytes = cmdStrList.Select(x => Convert.ToByte(x, 16)).ToArray(); - return bytes; - } - - /// - /// 构建电表参数设置-下发数据单元 - /// - /// - /// - private static List BuildAmmeterParameterSendDataUnit(List meterParameters) - { - var hexDatas = new List(); - - var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0'); - hexDatas.Add(countHex); - - for (int i = 0; i <= meterParameters.Count - 1; i++) - { - var meter = meterParameters[i]; - - //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'); - hexDatas.Add(pnHex); - - var baudRateBin = meter.BaudRate.DecToBin().PadLeft(3, '0'); - var portBin = meter.Port.DecToBin().PadLeft(5, '0'); - var baudRateAndPortHex = $"{baudRateBin}{portBin}".BinToHex().PadLeft(2, '0'); - hexDatas.Add(baudRateAndPortHex); - - var protocolTypeHex = ((int)meter.ProtocolType).DecToHex().PadLeft(2, '0'); - hexDatas.Add(protocolTypeHex); - - hexDatas.Add(meter.Address); - - hexDatas.Add(meter.Password.PadLeft(12, '0')); - - var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}"; - var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0'); - hexDatas.Add(rateNumberHex); - - var intBitNumberBin = (meter.IntegerBitNumber - 4).DecToBin().PadLeft(2, '0'); - var decBitNumberBin = (meter.DecimalBitNumber - 1).DecToBin().PadLeft(2, '0'); - var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}"; - var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0'); - hexDatas.Add(intAndDecBitNumberHex); - - hexDatas.Add(meter.CollectorAddress.PadLeft(12, '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); - } - - //高位在前,低位在后 - var datas = new List(); - foreach (var hexData in hexDatas) - { - if (hexData.Length == 2) - datas.Add(hexData); - else - { - var lst = hexData.StringToPairs(); - lst.Reverse(); - datas.AddRange(lst); - } - } - datas.AddRange(GetPW()); - return datas; - } - - /// - /// 构建水表参数设置-下发数据单元 - /// - /// - /// - private static List BuildWaterMeterParameterSendDataUnit(List meterParameters) - { - var hexDatas = new List(); - - var countHex = meterParameters.Count().DecToHex().PadLeft(4, '0'); - hexDatas.Add(countHex); - - for (int i = 0; i <= meterParameters.Count - 1; i++) - { - - var meter = meterParameters[i]; - var protocolType = (int)meter.ProtocolType; - - var currentProtocolType = protocolType; - if (protocolType == 43) - currentProtocolType = 1; - else if (protocolType > 32) currentProtocolType = 32; - - //TODO:无线水表 小数位 - if (currentProtocolType == 32 && meter.Address.Substring(0, 2) != "00") - { - var ejz = meter.Address.Substring(0, 2).HexToBin().PadLeft(8, '0'); - var xs = ejz.Substring(6, 2).BinToDec(); - var zs = ejz.Substring(0, 6).BinToDec(); - //userData.Add(new QGDW3671UserData() { Name = "整数位无线水表", Value = zs }); - //userData.Add(new QGDW3671UserData() { Name = "小数位无线水表", Value = xs }); - } - - var userCategoryNumber = meter.UserCategoryNumber; - var userSubclassNumber = meter.UserSubclassNumber; - - if (protocolType == 32) - userCategoryNumber = 1; - else if (protocolType == 45) - { - userCategoryNumber = 1; - userSubclassNumber = 9; - } - else if (protocolType == 1) - userSubclassNumber = 1; - - var indexHex = (i + 1).DecToHex().PadLeft(4, '0'); - hexDatas.Add(indexHex); - - var pnHex = meter.Pn.DecToHex().PadLeft(4, '0'); - hexDatas.Add(pnHex); - - var baudRateBin = meter.BaudRate.DecToBin().PadLeft(3, '0'); - var portBin = meter.Port.DecToBin().PadLeft(5, '0'); - var baudRateAndPortHex = $"{baudRateBin}{portBin}".BinToHex().PadLeft(2, '0'); - hexDatas.Add(baudRateAndPortHex); - - var protocolTypeHex = currentProtocolType.DecToHex().PadLeft(2, '0'); - hexDatas.Add(protocolTypeHex); - - hexDatas.Add(meter.Address); - - hexDatas.Add(meter.Password.PadLeft(12, '0')); - - var rateNumberBin = $"0000{meter.RateNumber.DecToBin().PadLeft(4, '0')}"; - var rateNumberHex = rateNumberBin.BinToHex().PadLeft(2, '0'); - hexDatas.Add(rateNumberHex); - - var intBitNumberBin = meter.IntegerBitNumber.DecToBin().PadLeft(2, '0'); - var decBitNumberBin = meter.DecimalBitNumber.DecToBin().PadLeft(2, '0'); - var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}"; - var intAndDecBitNumberHex = intAndDecBitNumberBin.BinToHex().PadLeft(2, '0'); - hexDatas.Add(intAndDecBitNumberHex); - - hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0')); - - 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); - } - - //高位在前,低位在后 - var datas = new List(); - foreach (var hexData in hexDatas) - { - if (hexData.Length == 2) - datas.Add(hexData); - else - { - var lst = hexData.StringToPairs(); - lst.Reverse(); - datas.AddRange(lst); - } - } - datas.AddRange(GetPW()); - return datas; - } - - - //AUX=消息认证码字段(PW,16个字节) - private static List GetPW() - { - var str = "00"; - var pWList = Enumerable.Repeat(str, pWLen).ToList(); - return pWList; - } - - - /// - /// 帧校验和 - /// - /// 用户数据区 - /// - private static string GetCS(List userData) - { - byte sum = 0; - foreach (var d in userData) - { - var b = Convert.ToByte(d, 16); - sum += b; - } - return sum.ToString("X2"); - } - - /// - /// 用户数据区 - /// - /// - /// - private static List BuildUserData(ReqParameter reqParameter, List? dataUnit) - { - var c = BuildC(reqParameter.FunCode, reqParameter.PRM); - var a = BuildAList(reqParameter.A, reqParameter.MSA); - - var linkUserData = BuildLinkUserData(reqParameter.AFN, reqParameter.Seq, - ((ReqParameter2)reqParameter).Pn, ((ReqParameter2)reqParameter).Fn, dataUnit); - - var list = new List() { c }; - list.AddRange(a); - list.AddRange(linkUserData); - return list; - } - - /// - /// 固定长度的报文头 起始字符+长度+长度+起始字符 - /// - /// - /// - private static List BuildHeaders(int length) - { - var headers = new List(); - headers.Add(startStr); - var l = BuildLength(length); - headers.AddRange(l); - headers.AddRange(l); - headers.Add(startStr); - return headers; - } - - /// - /// 长度 2字节 [用户数据区长度] - /// - /// - private static List BuildLength(int length1) - { - var binaryLen = length1.DecToBin(); - var protocolIdentification = Enum.Format(typeof(ProtocolIdentification), - ProtocolIdentification.本规约使用, "d").PadLeft(2, '0'); - var lenStr = $"{binaryLen}{protocolIdentification}"; - var hexLen = lenStr.BinToHex(); - hexLen = hexLen.PadLeft(4, '0'); - var list = hexLen.StringToPairs(); - list.Reverse(); - return list; - } - - /// - /// 控制域 - /// - /// 功能码 - /// - /// - /// - private static string BuildC(int funCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效) - { - var cMasterStationFunCodeHex = funCode.DecToBin(); - cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0'); - var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}"; - var hexC = strC.BinToHex().PadLeft(2, '0'); - return hexC; - } - - - /// - /// 地址域 3220 09872 - /// - /// 行政区划码 BCD码 3220=2032 - /// 逻辑地址 BIN 09872=2690=>9026 - /// 主站地址 BIN 0~127 - /// - private static List BuildAList(string a, int mSA) - { - var list = new List(); - - var a1 = a.Substring(0, 4); - var a1Pairs = a1.StringToPairs(); - a1Pairs.Reverse(); - list.AddRange(a1Pairs); - - var a2 = Convert.ToInt32(a.Substring(4)); - var decA2 = a2.DecToHex(); - var a2Pairs = decA2.PadLeft(4, '0').StringToPairs(); - a2Pairs.Reverse(); - list.AddRange(a2Pairs); - - //TODO:主站地址和组地址标志 - var a3Bin = $"{mSA.DecToBin().PadLeft(7, '0')}0"; - list.Add(a3Bin.BinToHex().PadLeft(2, '0')); - - return list; - } - - private static List BuildLinkUserData(AFN aFN, Seq seq, int pn, int fn, List? dataUnit) - { - var aFNValue = ((int)aFN).DecToHex().PadLeft(2, '0'); - var sEQ = BuildSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ); - var dA = BuildDA(pn); - var dT = BuildDT(fn); - var list = new List() { aFNValue, sEQ }; - list.AddRange(dA); - list.AddRange(dT); - - if (dataUnit != null) - { - list.AddRange(dataUnit); - } - //list.AddRange(GetDataUnit(aFN,seq)); - - if (seq.TpV == TpV.附加信息域中带时间标签) - list.AddRange(BuildTp("00")); - - return list; - } - - /// - /// 帧序列域 - /// - /// - /// - /// - /// - private static string BuildSEQ(TpV tpV, FIRFIN fIRFIN, CON cON, int pRSEQ) - { - var tpVValue = Enum.Format(typeof(TpV), - tpV, "d"); - var fIRFINValue = Enum.Format(typeof(FIRFIN), - fIRFIN, "d"); - var cONValue = (int)cON; - var sEQBin = $"{tpVValue}{fIRFINValue}{cONValue}{pRSEQ.DecToBin().PadLeft(4, '0')}"; - var hexSEQ = sEQBin.BinToHex().PadLeft(2, '0'); - return hexSEQ; - } - - /// - /// 信息点标识 - /// - /// 计量点 - /// - private static List BuildDA(int pn) - { - if (pn == 0) - return new List() { "00", "00" }; - var dA2 = (pn - 1) / 8 + 1;//信息点组从1开始 第几组 - var dA1 = pn - (dA2 - 1) * 8;//pn % 8 - var dA1Hex = "1".PadRight(dA1, '0').BinToHex();//对位信息 第几位 二进制有效位 - var dA2Hex = dA2.DecToHex(); - return new List() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') }; - - } - - /// - /// 数据单元标识 - /// - /// - /// - private static List BuildDT(int fn) - { - var dT2 = (fn - 1) / 8;//从零开始 第几组 - var dT1 = fn - dT2 * 8; - var dT1Hex = "1".PadRight(dT1, '0').BinToHex();//对位信息 第几位 二进制有效位 - var dT2Hex = dT2.DecToHex(); - return new List() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') }; - } - - /// - /// 时间标签 - /// - /// 启动帧帧序号计数器PFC 1字节 - /// 允许发送传输延时时间 min 1字节 - /// - private static List BuildTp(string pFC = "00", int delayTime = 0) - { - var now = DateTime.Now; // 获取当前时间 - var seconds = now.Second.ToString().PadLeft(2, '0'); // 获取当前秒数 - var minutes = now.Minute.ToString().PadLeft(2, '0'); // 获取当前分钟数 - var hours = now.Hour.ToString().PadLeft(2, '0'); // 获取当前小时数 - var day = now.Day.ToString().PadLeft(2, '0'); // 获取当前日期的日数 - return new List() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') }; - } - - #endregion - - #region 645下行命令 - - - /// - /// 构建电表阀控下发数据单元 - /// - /// 电表地址 - /// 特殊控制码 - /// 密码 - /// 是否为开阀 - /// 型号码 - /// - public static List BuildAmmeterValveControlSendDataUnit(string ammeterAddress, string specialControlCode, string password, bool state, string modelCode = "") - { - var code = string.Empty; - - if (state) - { - if (string.IsNullOrEmpty(specialControlCode)) - code = "1B"; - else - code = specialControlCode == "1B" || specialControlCode == "1C" ? specialControlCode : "1C"; - } - else - code = "1A";//跳闸 - - if (specialControlCode == "1W") - { - if (state) - code = "1A"; - else - code = "1C"; - } - - var pwdLevel = "02"; - if (modelCode == "HL_DTSU2625" || modelCode == "DDZY9866") - pwdLevel = "04"; - else if (modelCode == "DDS2705") - pwdLevel = "03"; //不带安全认证密级 - - if (!string.IsNullOrWhiteSpace(password) && password.Contains("|")) - { - var sp = password.Split('|'); - pwdLevel = sp[1]; - password = sp[0]; - } - - var strDate = DateTime.Now.AddYears(3).ToString("000012ddMMyy").StrAddSpan();//命令有效截止时间 - if (specialControlCode == "1D" || modelCode == "SZBD_DDZY1225") - strDate = "FF FF FF FF FF FF"; - var strP = password.StrAddSpan().StrReverseOrder(); - var strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + code + " 00 " + strDate; - var dataUnit = strSJY.Replace(" ", "").StringToPairs(); - var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit); - return dataList; - - //string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2"); - //string strReturn = "68 " + address.StrAddSpan().StrReverseOrder() + " 68 1C " + strLen + " " + strSJY.StrAddHex33() + " "; - //string strSum = strReturn.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); - //strReturn += strSum.Substring(strSum.Length - 2) + " 16"; - //return strReturn.Split(' ').ToList(); - } - - /// - /// 构建电表保电下发数据单元 - /// - /// 电表地址 - /// - /// true 保电 false 保电解除 - /// 型号码 - /// - public static List BuildAmmeterLockSendDataUnit(string ammeterAddress, string password, bool state, string modelCode = "") - { - var code = state ? "3A" : "3B"; - - var strDate = (code + DateTime.Now.AddDays(1).ToString("00000012ddMMyy")).StrAddSpan(); - - if (modelCode == "SZBD_DDZY1225") - strDate = $"{code} 00 FF FF FF FF FF FF"; - - var strP = password.StrAddSpan().StrReverseOrder(); - var strSJY = " 02 " + strP + " 01 00 00 00 " + strDate; - - var dataUnit = strSJY.Replace(" ", "").StringToPairs(); - var dataList = Build645SendCommand(ammeterAddress, "1C", dataUnit); - return dataList; - } - - /// - /// 构建电表认证下发数据单元 - /// - /// 电表地址 - /// - /// - /// - public static List BuildAmmeterIdentitySendDataUnit(string ammeterAddress, string ramDon, string maco) - { - var codeList = "070004FF".StringToPairs(); - codeList.Reverse(); - - var ramDonList = ramDon.StringToPairs(); - ramDonList.Reverse(); - - var macoList = maco.StringToPairs(); - macoList.Reverse(); - - var dataUnit = new List(); - dataUnit.AddRange(codeList); - dataUnit.AddRange(ramDonList); - dataUnit.AddRange(macoList); - var dataList = Build645SendCommand(ammeterAddress, "03", dataUnit); - return dataList; - } - - /// - /// 构建电表清零下发数据单元 - /// - /// 电表地址 - /// - /// - 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(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协议下发命令 - /// - /// 电表地址 - /// 控制码 - /// 数据域 发送方按字节进行加33处理,接收方按字节减33 - /// - public static List Build645SendCommand(string ammeterAddress, string controlCode, List? dataUnit) - { - var cmdStrList = new List(); - cmdStrList.Add(startStr); - - ammeterAddress = ammeterAddress.PadLeft(12, '0'); - var addressList = ammeterAddress.StringToPairs(); - addressList.Reverse(); - cmdStrList.AddRange(addressList); - - cmdStrList.Add(startStr); - - cmdStrList.Add(controlCode); - - var len = dataUnit != null ? dataUnit.Count.DecToHex().PadLeft(2, '0') : "00"; - cmdStrList.Add(len); - - if (dataUnit != null) - { - cmdStrList.AddRange(dataUnit.AddHex33()); - } - - var strSum = cmdStrList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); - strSum = strSum.Substring(strSum.Length - 2); - cmdStrList.Add(strSum); - cmdStrList.Add(endStr); - - return cmdStrList; - } - - /// - /// 威胜表的超功率(第一路恶性负载超功率判断阀值) - /// - /// - /// - /// - /// - /// - 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(ammeterAddress, password, dataMark, data); - } - /// - /// 威胜表的超功率(超功率开关) - /// - /// - /// - /// - /// - public static List AssembleWsOnSupperPower(string ammeterAddress, string password, bool isOn = true) - { - var data = new string[] { (isOn ? "01" : "00") }; - return AssembleWrite(ammeterAddress, password, "0E400001", data); - } - /// - /// 威胜表的超功率(第一路恶性负载绝对功率判断阈值) - /// - /// - /// - /// - /// - /// - 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(ammeterAddress, password, dataMark, data); - } - /// - /// 威胜表的超功率(第一路恶性负载功率因数判断阀值) - /// - /// - /// - /// - /// - /// - 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(ammeterAddress, password, dataMark, data); - } - - /// - /// 构建写数据 - /// - /// - /// - /// - /// - /// - public static List AssembleWrite(string ammeterAddress, string password, string di0_3, string[] data) - { - var returnList = new List(); - returnList.Add(startStr); - - var addressList = ammeterAddress.StringToPairs(); - addressList.Reverse(); - returnList.AddRange(addressList); - - returnList.Add(startStr); - returnList.Add("14"); - - var len = (12 + data.Length).ToString("X2"); - returnList.Add(len); - - - var di03List = di0_3.StringToPairs(); - di03List.Reverse(); - di03List.Add("02"); - - var pwdList = password.StringToPairs(); - pwdList.Reverse(); - di03List.AddRange(pwdList); - - var mList = new List() { "00", "11", "22", "33" }; - di03List.AddRange(mList); - di03List.AddRange(data); - var listAdd33 = di03List.AddHex33(); - - returnList.AddRange(listAdd33); - - var strSum = returnList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); - var cs = strSum.Substring(strSum.Length - 2); - returnList.Add(cs); - returnList.Add(endStr); - - return returnList; - } - - /// - /// 生成软编程指令 - /// 型号编码 - /// - /// - private static List SoftProgram(string ammeterAddress, string modelCode,string password) - { - string bccmd = string.Empty; - if (modelCode == "DDS71") - { - - bccmd = "68 AA AA AA AA AA AA 68 04 07 4E F4 35 BB BB BB 32"; - } - else - { - bccmd = "68 AA AA AA AA AA AA 68 14 10 41 35 33 41 37 33 33 33 34 33 33 33 77 66 55 44"; - } - - //替换密码 - var passwordList = password.StringToPairs(); - passwordList.Reverse(); - passwordList = passwordList.AddHex33(); - var passwordStr = string.Join(" ", passwordList); - bccmd = bccmd.Replace("BB BB BB", passwordStr); - //替换表地址 - var addressList = ammeterAddress.StringToPairs(); - addressList.Reverse(); - var addressStr = string.Join(" ", addressList); - bccmd = bccmd.Replace("AA AA AA AA AA AA", addressStr); - var fm = bccmd.Split(' ').ToList(); - //生成CRC - var cRC = GetCRC(fm); - fm.Add(cRC); - fm.Add("16"); - - 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 下行命令 - - /// - /// 标准 188协议阀控 - /// - /// - /// 表计类型 - /// - public static List BuildConfirm188WaterValve(string waterMeterAddress, bool state, string mtype = "10") - { - if (string.IsNullOrWhiteSpace(waterMeterAddress)) return null; - - var dataUnit = new List() { "A0", "17", "00", state ? "55" : "99" }; - - var dataList = Build188SendCommand(waterMeterAddress, "04", dataUnit); - - return dataList; - } - - /// - /// 构建188水表抄读下发数据单元 - /// - /// - /// - public static List Build188WaterMeterReadingSendDataUnit(string waterMeterAddress) - { - - var dataUnit = new List() { "1F", "90", "00" }; - var dataList = Build188SendCommand(waterMeterAddress, "01", dataUnit); - - return dataList; - } - - /// - /// 构建188协议下发命令 - /// - /// 水表地址 - /// 控制码 - /// 数据域 - /// 表类型 - /// - public static List Build188SendCommand(string waterMeterAddress, string controlCode, List? dataUnit = null, string meterType = "10") - { - //address.Substring(address.Length - 12, 12) - var cmdStrList = new List(); - cmdStrList.Add(startStr); - cmdStrList.Add(meterType); - - waterMeterAddress = waterMeterAddress.PadLeft(14, '0'); - var addressList = waterMeterAddress.StringToPairs(); - addressList.Reverse(); - cmdStrList.AddRange(addressList); - - //控制码 - cmdStrList.Add(controlCode); - - var len = dataUnit != null ? dataUnit.Count.DecToHex().PadLeft(2, '0') : "00"; - cmdStrList.Add(len); - if (dataUnit != null) - { - cmdStrList.AddRange(dataUnit); - } - - var strSum = cmdStrList.Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); - strSum = strSum.Substring(strSum.Length - 2); - cmdStrList.Add(strSum); - cmdStrList.Add(endStr); - - return cmdStrList; - } - - /// - /// 组装水表阀控 - /// - /// 水表地址 - /// The password. - /// The poprotocol. - /// if set to true [isopenvalve]. - /// - public static List? WaterMeterValveControl(string waterMeterAddress, string password, int protocol, bool state) - { - List? turnData = null; - if (protocol == 1) - turnData = GetControlCode97(waterMeterAddress.Substring(waterMeterAddress.Length - 12, 12), password, state ? "3355" : "9966");//开阀/关阀 - else if (protocol == 30) - turnData = GetControlCode07(waterMeterAddress.Substring(waterMeterAddress.Length - 12, 12), password, state ? "3355" : "9966");//开阀/关阀 - return turnData; - } - - private static List GetControlCode97(string waterMeterAddress, string password, string valueCode) - { - var dataList = new List(); - var passwordList = password.StringToPairs(); - passwordList.Reverse(); - - var valueCodeList = valueCode.StringToPairs(); - valueCodeList.Reverse(); - - dataList.AddRange(valueCodeList); - dataList.AddRange(passwordList); - dataList.AddRange(valueCodeList); - - return GetCode(waterMeterAddress, "04", dataList); - } - - private static List GetControlCode07(string waterMeterAddress, string password, string valueCode) - { - var dataList = new List(); - dataList.Add("02"); - - var passwordList = password.StringToPairs(); - passwordList.Reverse(); - dataList.AddRange(passwordList); - dataList.AddRange("01000000".StringToPairs()); - - dataList.AddRange(valueCode.StringToPairs()); - - dataList.Add("00"); - - var time = DateTime.Now.AddDays(1).ToString("yyMMddHHmmss"); - var timeList = time.StringToPairs(); - timeList.Reverse(); - dataList.AddRange(timeList); - - return GetCode(waterMeterAddress, "1C", dataList); - } - - public static List GetCode(string waterMeterAddress, string controlCode, List childDataList) - { - var dataList = new List { startStr }; - - waterMeterAddress = waterMeterAddress.PadLeft(12, '0'); - var addressList = waterMeterAddress.StringToPairs(); - addressList.Reverse(); - dataList.AddRange(addressList); - - dataList.Add(startStr); - dataList.Add(controlCode); - - var num = childDataList.Count; - dataList.Add(num.ToString("X2")); - - dataList.AddRange(childDataList.AddHex33()); - - var cs = dataList.Select(it => Convert.ToInt32(it, 16)).Sum().ToString("X2"); - cs = cs.Substring(cs.Length - 2, 2); - dataList.Add(cs); - - dataList.Add(endStr); - - return dataList; + return hexStringList; } public static string GetCRC(List inputFrm, int startIndex = 0) @@ -2298,47 +141,6 @@ namespace JiShe.CollectBus.Common.Extensions 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) - { - return null; - } - - switch (chunk) - { - case CommandChunkEnum188.A: - var aHexList = hexStringList[(int)CommandChunkEnum188.A].Take(7).ToList(); - aHexList.Reverse(); - return string.Join("", aHexList.Skip(1).Take(6).ToList()); - case CommandChunkEnum188.C: - var cHex = hexStringList[(int)CommandChunkEnum188.C]; - return cHex; - case CommandChunkEnum188.Data: - var lenIndex = (int)CommandChunkEnum188.L; - var len = hexStringList[lenIndex].HexToDec(); - - //验证长度 2=(帧校验和+结束字符) - if (hexStringList.Count - 2 != 11 + len) - return null; - - var dataHexList = hexStringList.Skip(11).Take(len).ToList(); - return dataHexList; - default: - throw new ArgumentOutOfRangeException(nameof(chunk), chunk, null); - } - } - - //public double AnalyzeCurrentTotalRate(List hexList) - //{ - // var str = string.Join("", hexList); - // var number = Convert.ToInt32(str) * 0.01; - // return number; - //} - - #endregion - } diff --git a/src/JiShe.CollectBus.Common/Models/ReqParameter.cs b/src/JiShe.CollectBus.Common/Models/ReqParameter.cs index 0d55825..57398a2 100644 --- a/src/JiShe.CollectBus.Common/Models/ReqParameter.cs +++ b/src/JiShe.CollectBus.Common/Models/ReqParameter.cs @@ -168,4 +168,17 @@ namespace JiShe.CollectBus.Common.Models public string StartTime { get; set; } public string EndTime { get; set; } } + + public class PnFn + { + public int Pn { get; set; } + public int Fn { get; set; } + + public PnFn(int pn, int fn) + { + Pn = pn; + Fn = fn; + } + } + } diff --git a/src/JiShe.CollectBus.Domain/Analyze3761Data.cs b/src/JiShe.CollectBus.Domain/Analyze3761Data.cs new file mode 100644 index 0000000..ec2373a --- /dev/null +++ b/src/JiShe.CollectBus.Domain/Analyze3761Data.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Domain.Entities; + +namespace JiShe.CollectBus +{ + public class Analyze3761Data:AggregateRoot + { + public int MeterId { get; set; } + + public int AFN { get; set; } + + public int FN { get; set; } + + public string Text { get; set; } + + public List DataUpChilds { get; set; } + } + + public class Analyze3761DataUpChild + { + public Analyze3761DataUpChild(int id,string name,string value,int sort) + { + Id = id; + Name = name; + Value = value; + Sort = sort; + } + + public int Id { get; set; } + + public string Name { get; set; } + + public string Value { get; set; } + + public int Sort { get; set; } + + public List DataUpChilds { get; set; } + + } +} diff --git a/src/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs b/src/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs index cc7a278..1aa68c4 100644 --- a/src/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs +++ b/src/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs @@ -13,6 +13,13 @@ using Volo.Abp.Domain.Repositories; using System; using System.Runtime.CompilerServices; using MassTransit.Internals.GraphValidation; +using JiShe.CollectBus.Devices; +using JiShe.CollectBus.Common.BuildSendDatas; +using JiShe.CollectBus.Protocol.Contracts.AnalysisData; +using Newtonsoft.Json.Linq; +using System.Diagnostics.Metrics; +using Newtonsoft.Json; +using TouchSocket.Core; namespace JiShe.CollectBus.Protocol.Contracts.Abstracts { @@ -88,7 +95,7 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts Pn = 0, Fn = 1 }; - var bytes = HexStringExtensions.BuildSendCommandBytes(reqParam); + var bytes = Build3761SendData.BuildSendCommandBytes(reqParam); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { ClientId = messageReceived.ClientId, DeviceNo = messageReceived.DeviceNo, Message = bytes, Type = IssuedEventType.Login, MessageId = messageReceived.MessageId }); } @@ -127,7 +134,7 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts Pn = 0, Fn = 1 }; - var bytes = HexStringExtensions.BuildSendCommandBytes(reqParam); + var bytes = Build3761SendData.BuildSendCommandBytes(reqParam); await _capBus.PublishAsync(ProtocolConst.SubscriberIssuedEventName, new IssuedEventMessage { ClientId = messageReceived.ClientId, DeviceNo = messageReceived.DeviceNo, Message = bytes, Type = IssuedEventType.Heartbeat, MessageId = messageReceived.MessageId }); } } @@ -343,8 +350,8 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts /// /// /// - /// - public virtual F25ReadingAnalyze AnalyzeF25ReadingDataAsync(MessageReceivedHeartbeat messageReceived, Action? sendAction = null) + /// //F25ReadingAnalyze + public virtual Analyze3761Data AnalyzeF25ReadingDataAsync(MessageReceivedHeartbeat messageReceived, Action? sendAction = null) { var hexDatas = GetHexDatas(messageReceived.MessageHexString); //A.15 分时日月年 @@ -425,35 +432,69 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts var crntApparentPowerOfCHexs = hexDatas.Skip((int)F25DataItemEnum.CrntApparentPowerOfC).Take(3).ToList(); var crntApparentPowerOfC = AnalyzeDataAccordingToA09(crntApparentPowerOfCHexs[0], crntApparentPowerOfCHexs[1], crntApparentPowerOfCHexs[2]); - var f25ReadingAnalyze = new F25ReadingAnalyze() + return new Analyze3761Data() { - ReadingTime = readingTime.ToLocalTime(), - CrntTotalActivePower = crntTotalActivePower, - CrntActivePowerOfA = crntActivePowerOfA, - CrntActivePowerOfB = crntActivePowerOfB, - CrntActivePowerOfC = crntActivePowerOfC, - CrntTotalReactivePower = crntTotalReactivePower, - CrntReactivePowerOfA = crntReactivePowerOfA, - CrntReactivePowerOfB = crntReactivePowerOfB, - CrntReactivePowerOfC = crntReactivePowerOfC, - CrntTotalPowerFactor = crntTotalPowerFactor, - CrntPowerFactorOfA = crntPowerFactorOfA, - CrntPowerFactorOfB = crntPowerFactorOfB, - CrntPowerFactorOfC = crntPowerFactorOfC, - CrntVoltageOfA = crntVoltageOfA, - CrntVoltageOfB = crntVoltageOfB, - CrntVoltageOfC = crntVoltageOfC, - CrntCurrentOfA = crntCurrentOfA, - CrntCurrentOfB = crntCurrentOfB, - CrntCurrentOfC = crntCurrentOfC, - CrntZeroSequenceCurrent = crntZeroSequenceCurrent, - CrntTotalApparentPower = crntTotalApparentPower, - CrntApparentPowerOfA = crntApparentPowerOfA, - CrntApparentPowerOfB = crntApparentPowerOfB, - CrntApparentPowerOfC = crntApparentPowerOfC + AFN = 12, + FN = 25, + Text = "当前三相及总有/无功功率功率因数", + DataUpChilds = new List() + { + new Analyze3761DataUpChild(1,"终端抄表时间",readingTime.ToString(),1), + new Analyze3761DataUpChild(2,"当前总有功功率",crntTotalActivePower.ToString(),2), + new Analyze3761DataUpChild(3,"当前A相有功功率",crntActivePowerOfA.ToString(),3), + new Analyze3761DataUpChild(4,"当前B相有功功率",crntActivePowerOfB.ToString(),4), + new Analyze3761DataUpChild(5,"当前C相有功功率",crntActivePowerOfC.ToString(),5), + new Analyze3761DataUpChild(6,"当前总无功功率",crntTotalReactivePower.ToString(),6), + new Analyze3761DataUpChild(7,"当前A相无功功率",crntReactivePowerOfA.ToString(),7), + new Analyze3761DataUpChild(8,"当前B相无功功率",crntReactivePowerOfB.ToString(),8), + new Analyze3761DataUpChild(9,"当前C相无功功率",crntReactivePowerOfC.ToString(),9), + new Analyze3761DataUpChild(10,"当前总功率因数",crntTotalPowerFactor.ToString(),10), + new Analyze3761DataUpChild(11,"当前A相功率因数",crntPowerFactorOfA.ToString(),11), + new Analyze3761DataUpChild(12,"当前B相功率因数",crntPowerFactorOfB.ToString(),12), + new Analyze3761DataUpChild(13,"当前C相功率因数",crntPowerFactorOfC.ToString(),13), + new Analyze3761DataUpChild(14,"当前A相电压",crntVoltageOfA.ToString(),14), + new Analyze3761DataUpChild(15,"当前B相电压",crntVoltageOfB.ToString(),15), + new Analyze3761DataUpChild(16,"当前C相电压",crntVoltageOfC.ToString(),16), + new Analyze3761DataUpChild(17,"当前A相电流",crntCurrentOfA.ToString(),17), + new Analyze3761DataUpChild(18,"当前B相电流",crntCurrentOfB.ToString(),18), + new Analyze3761DataUpChild(19,"当前C相电流",crntCurrentOfC.ToString(),19), + new Analyze3761DataUpChild(20,"当前零序电流",crntZeroSequenceCurrent.ToString(),20), + new Analyze3761DataUpChild(21,"当前总视在功率",crntTotalApparentPower.ToString(),21), + new Analyze3761DataUpChild(22,"当前A相视在功率",crntApparentPowerOfA.ToString(),22), + new Analyze3761DataUpChild(23,"当前B相视在功率",crntApparentPowerOfB.ToString(),23), + new Analyze3761DataUpChild(24,"当前C相视在功率",crntApparentPowerOfC.ToString(),24), + } }; - return f25ReadingAnalyze; + //var f25ReadingAnalyze = new F25ReadingAnalyze() + //{ + // ReadingTime = readingTime.ToLocalTime(), + // CrntTotalActivePower = crntTotalActivePower, + // CrntActivePowerOfA = crntActivePowerOfA, + // CrntActivePowerOfB = crntActivePowerOfB, + // CrntActivePowerOfC = crntActivePowerOfC, + // CrntTotalReactivePower = crntTotalReactivePower, + // CrntReactivePowerOfA = crntReactivePowerOfA, + // CrntReactivePowerOfB = crntReactivePowerOfB, + // CrntReactivePowerOfC = crntReactivePowerOfC, + // CrntTotalPowerFactor = crntTotalPowerFactor, + // CrntPowerFactorOfA = crntPowerFactorOfA, + // CrntPowerFactorOfB = crntPowerFactorOfB, + // CrntPowerFactorOfC = crntPowerFactorOfC, + // CrntVoltageOfA = crntVoltageOfA, + // CrntVoltageOfB = crntVoltageOfB, + // CrntVoltageOfC = crntVoltageOfC, + // CrntCurrentOfA = crntCurrentOfA, + // CrntCurrentOfB = crntCurrentOfB, + // CrntCurrentOfC = crntCurrentOfC, + // CrntZeroSequenceCurrent = crntZeroSequenceCurrent, + // CrntTotalApparentPower = crntTotalApparentPower, + // CrntApparentPowerOfA = crntApparentPowerOfA, + // CrntApparentPowerOfB = crntApparentPowerOfB, + // CrntApparentPowerOfC = crntApparentPowerOfC + //}; + + //return f25ReadingAnalyze; } @@ -462,8 +503,8 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts /// /// /// - /// - public virtual TerminalVersionInfoAnalyze AnalyzeTerminalVersionInfoReadingDataAsync(MessageReceivedHeartbeat messageReceived, Action? sendAction = null) + /// //TerminalVersionInfoAnalyze + public virtual Analyze3761Data AnalyzeTerminalVersionInfoReadingDataAsync(MessageReceivedHeartbeat messageReceived, Action? sendAction = null) { var hexDatas = GetHexDatas(messageReceived.MessageHexString); @@ -473,22 +514,39 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts var softwareReleaseDateList = hexDatas.Skip((int)TerminalVersionInfoEnum.SoftwareReleaseDate).Take(3).ToList(); var softwareReleaseDate = $"20{AnalyzeDataAccordingToA20(softwareReleaseDateList[0], softwareReleaseDateList[1], softwareReleaseDateList[2])}";//软件发布日期 var capacityInformationCode = string.Join("", hexDatas.Skip((int)TerminalVersionInfoEnum.CapacityInformationCode).Take(11).Select(s => (char)s.HexToDec()));//容量信息码 - var protocolVersionNo = string.Join("", hexDatas.Skip((int)TerminalVersionInfoEnum.ProtocolVersionNo).Take(4).Select(s => (char)s.HexToDec()));//容量信息码 + var protocolVersionNo = string.Join("", hexDatas.Skip((int)TerminalVersionInfoEnum.ProtocolVersionNo).Take(4).Select(s => (char)s.HexToDec()));//通信协议编号 var hardwareVersionNo = string.Join("", hexDatas.Skip((int)TerminalVersionInfoEnum.HardwareVersionNo).Take(4).Select(s => (char)s.HexToDec()));//硬件版本号 var hardwareReleaseDateList = hexDatas.Skip((int)TerminalVersionInfoEnum.HardwareReleaseDate).Take(3).ToList(); var hardwareReleaseDate = $"20{AnalyzeDataAccordingToA20(hardwareReleaseDateList[0], hardwareReleaseDateList[1], hardwareReleaseDateList[2])}";//软件发布日期 - - return new TerminalVersionInfoAnalyze() + + return new Analyze3761Data() { - MakerNo = makerNo, - DeviceNo = deviceNo, - SoftwareVersionNo = softwareVersionNo, - SoftwareReleaseDate = DateTime.Parse(softwareReleaseDate).ToLocalTime(), - CapacityInformationCode = capacityInformationCode, - ProtocolVersionNo = protocolVersionNo, - HardwareVersionNo = hardwareVersionNo, - HardwareReleaseDate = DateTime.Parse(hardwareReleaseDate).ToLocalTime() + AFN = 09, + FN = 1, + Text = "终端版本信息", + DataUpChilds = new List() + { + new Analyze3761DataUpChild(1,"厂商代码",makerNo.ToString(),1), + new Analyze3761DataUpChild(2,"设备编号",deviceNo.ToString(),2), + new Analyze3761DataUpChild(3,"软件版本号",softwareVersionNo.ToString(),3), + new Analyze3761DataUpChild(4,"软件发布日期",softwareReleaseDate.ToString(),4), + new Analyze3761DataUpChild(5,"容量信息码",capacityInformationCode.ToString(),5), + new Analyze3761DataUpChild(6,"通信协议编号",protocolVersionNo.ToString(),6), + new Analyze3761DataUpChild(7,"硬件版本号",hardwareVersionNo.ToString(),7), + new Analyze3761DataUpChild(8,"软件发布日期",hardwareReleaseDate.ToString(),8), + } }; + //return new TerminalVersionInfoAnalyze() + //{ + // MakerNo = makerNo, + // DeviceNo = deviceNo, + // SoftwareVersionNo = softwareVersionNo, + // SoftwareReleaseDate = DateTime.Parse(softwareReleaseDate).ToLocalTime(), + // CapacityInformationCode = capacityInformationCode, + // ProtocolVersionNo = protocolVersionNo, + // HardwareVersionNo = hardwareVersionNo, + // HardwareReleaseDate = DateTime.Parse(hardwareReleaseDate).ToLocalTime() + //}; } /// @@ -497,7 +555,7 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts /// /// /// - public virtual async Task AnalyzeATypeOfDataItems49ReadingDataAsync(MessageReceivedHeartbeat messageReceived, Action? sendAction = null) + public virtual Analyze3761Data AnalyzeATypeOfDataItems49ReadingDataAsync(MessageReceivedHeartbeat messageReceived, Action? sendAction = null) { var hexDatas = GetHexDatas(messageReceived.MessageHexString); @@ -518,6 +576,34 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts var icList = hexDatas.Skip((int)ATypeOfDataItems49.Ic).Take(2).ToList(); var ic = AnalyzeDataAccordingToA05(icList[0], icList[1]); + + return new Analyze3761Data() + { + AFN = 12, + FN = 49, + Text = "相位角", + DataUpChilds = new List() + { + new Analyze3761DataUpChild(1,"UabUa相位角",uabUa.ToString(),1), + new Analyze3761DataUpChild(2,"Ub相位角",ub.ToString(),2), + new Analyze3761DataUpChild(3,"UcbUc相位角",ucbUc.ToString(),3), + new Analyze3761DataUpChild(4,"Ia相位角",ia.ToString(),4), + new Analyze3761DataUpChild(5,"Ib相位角",ib.ToString(),5), + new Analyze3761DataUpChild(6,"Ic相位角",ic.ToString(),6), + } + }; + } + + /// + /// 解析终端时间抄读 + /// + /// + /// + + public virtual void AnalyzeTerminalTimeReadingDataAsync(MessageReceivedHeartbeat messageReceived, Action? sendAction = null) + { + var hexDatas = GetHexDatas(messageReceived.MessageHexString); + var time = Appendix.Appendix_A1(hexDatas.Take(6).ToList()); } /// @@ -716,7 +802,6 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts return value; } - /// /// 解析透明转发 应答 /// @@ -986,13 +1071,61 @@ namespace JiShe.CollectBus.Protocol.Contracts.Abstracts var singleDigitNumber = bin2.Substring(0, 4).BinToDec();//个位 var deciles = bin1.Substring(4).BinToDec();//十分位 - var value = decimal.Parse($"{hundredDigitNumbers}{tenDigitNumber}{singleDigitNumber}.{deciles}{percentileAndThousandthPercentile}"); return value; } #endregion + #region 645 + /// + /// 解析读取表地址 + /// + /// + /// + public List AnalyzeAmmeterReadMeterAddress_10_105(List dataList) + { + var values = new List(); + //表地址 + var addressList = dataList.GetRange(1, 6); + addressList.Reverse(); + var address = string.Join("", addressList); + values.Add(address); + //控制码 + var controlCode = dataList.GetRange(8, 1)[0]; + values.Add(controlCode); + //长度 + var len = dataList.GetRange(9, 1)[0].HexToDec(); + //values.Add(len.ToString()); + //数据域 + var dataField = dataList.GetRange(10, len); + if (dataField.Count > 0) + { + string dataMark = string.Join("", dataField.GetRange(0, 4).AddHex33()); + values.Add(dataMark);//数据标识 + var readValue = dataField.GetRange(4, len - 4).ReduceHex33();//值 + readValue.Reverse(); + //var valueData = GetValue>(readValue, (AppendixEnums)Enum.Parse(typeof(AppendixEnums), dataMark)); + values.AddRange(readValue); + } + return values; + } + + + public void AnalyzeAmmeterReadMeterAddress_10_103(List dataList) + { + var data = AnalyzeAmmeterReadMeterAddress_10_105(dataList); + var validData = data[2].Equals("94") ? true : false; + var remark = validData ? "成功" : "失败"; + } + + public void AnalyzeAutoUpSwtichRead_0A_68(List dataList) + { + var isOpen = dataList[4].Equals("55"); + } + + #endregion + #region 188 public void AnalyzeWaterMeter188Data(List dataList) diff --git a/src/JiShe.CollectBus.Protocol.Contracts/AnalysisData/Appendix.cs b/src/JiShe.CollectBus.Protocol.Contracts/AnalysisData/Appendix.cs new file mode 100644 index 0000000..f68268c --- /dev/null +++ b/src/JiShe.CollectBus.Protocol.Contracts/AnalysisData/Appendix.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using JiShe.CollectBus.Common.Extensions; + +namespace JiShe.CollectBus.Protocol.Contracts.AnalysisData +{ + /// + /// 附录 + /// + public static class Appendix + { + /// + /// 附录1 A1格式 + /// + /// + public static string Appendix_A1(List data) + { + var seconds = data[0]; + var minutes = data[1]; + var hours = data[2]; + var day = data[3]; + var binString = data[4].HexToBin(); + var months = binString.Substring(3, 1).BinToDec() * 10 + Convert.ToInt32(binString.Substring(4, 4).BinToHex()); + var week = binString.Substring(0, 3).BinToHex(); + var year = $"{DateTime.Now.ToString("yyyy").Substring(0, 2)}{data[5]}"; + return $"{year}-{months.ToString().PadLeft(2, '0')}-{day} {hours}:{minutes}:{seconds}_{week}"; + } + + } +}