#region << 版 本 注 释 >> /*-------------------------------------------------------------------- * 版权所有 (c) 2025 WenJY 保留所有权利。 * CLR版本:4.0.30319.42000 * 机器名称:Mr.Wen's MacBook Pro * 命名空间:Sln.Iot.Business * 唯一标识:F35152F4-9983-4881-AB1C-F9561EFAF534 * * 创建者:WenJY * 电子邮箱: * 创建时间:2025-05-20 10:30:12 * 版本:V1.0.0 * 描述: * *-------------------------------------------------------------------- * 修改人: * 时间: * 修改说明: * * 版本:V1.0.0 *--------------------------------------------------------------------*/ #endregion << 版 本 注 释 >> using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Sln.Iot.Business.@base; using Sln.Iot.Common; using Sln.Iot.Config; using Sln.Iot.Model.dao; using Sln.Iot.Model.dto; using Sln.Iot.Repository.service; using Sln.Iot.Serilog; using Sln.Iot.Socket.Adapter; using TouchSocket.Core; using TouchSocket.Sockets; namespace Sln.Iot.Business { /// /// 电能数据 /// public class ElectricBusiness:BaseBusiness { private Dictionary _lastCollectTimeDict = new Dictionary(); private readonly IRecordDnbInstantService? _service; public ElectricBusiness(SerilogHelper logger, AppConfig appConfig, StringChange stringChange, IRecordDnbInstantService? service) : base(logger, appConfig, stringChange) { _service = service; } public override FilterResult BufferAnalysis(ISocketClient client, BufferRequestInfo requestInfo, int bodyLength) { ByteBlock byteBlock = new ByteBlock(requestInfo.Body); if (byteBlock.CanReadLen < 1) { return FilterResult.Cache; } int pos = byteBlock.Pos; try { List result = new List(); var amount = requestInfo.BufferLength / bodyLength; _logger.Info($"收到{amount}个电表数据,开始循环解析......"); for (int i = 0; i < amount; i++) { RecordDnbInstant dnbInstant = new RecordDnbInstant(); #region 表号解析 byteBlock.Read(out byte[] b_MeterID, 2); var decParts = b_MeterID.Select(b => $"{b:D2}").ToArray(); var equipId = $"{requestInfo.ColletEquipCode}_{decParts[0]}{decParts[1]}"; #endregion dnbInstant.monitorId = equipId; do { byteBlock.Read(out byte[] b_UA_flag, 2); base._stringChange.ConvertBytesToUInt16(b_UA_flag, out uint flag); switch (flag) { case CommParams.AU: //A项电压 byteBlock.Read(out byte[] b_UA, 4); base._stringChange.SwapBytes(ref b_UA); float f_UA = BitConverter.ToSingle(b_UA, 0); ValueIsNan(ref f_UA); dnbInstant.vA = (decimal) f_UA; break; case CommParams.BU: //B项电压 byteBlock.Read(out byte[] b_UB, 4); base._stringChange.SwapBytes(ref b_UB); float f_UB = BitConverter.ToSingle(b_UB, 0); ValueIsNan(ref f_UB); dnbInstant.vB = (decimal) f_UB; break; case CommParams.CU: //C项电压 byteBlock.Read(out byte[] b_UC, 4); base._stringChange.SwapBytes(ref b_UC); float f_UC = BitConverter.ToSingle(b_UC, 0); ValueIsNan(ref f_UC); dnbInstant.vC = (decimal) f_UC; break; case CommParams.AI: //A项电流 byteBlock.Read(out byte[] b_IA, 4); base._stringChange.SwapBytes(ref b_IA); float f_IA = BitConverter.ToSingle(b_IA, 0); ValueIsNan(ref f_IA); dnbInstant.iA = (decimal) f_IA; break; case CommParams.BI: //B项电流 byteBlock.Read(out byte[] b_IB, 4); base._stringChange.SwapBytes(ref b_IB); float f_IB = BitConverter.ToSingle(b_IB, 0); ValueIsNan(ref f_IB); dnbInstant.iB = (decimal) f_IB; break; case CommParams.CI: //C项电流 byteBlock.Read(out byte[] b_IC, 4); base._stringChange.SwapBytes(ref b_IC); float f_IC = BitConverter.ToSingle(b_IC, 0); ValueIsNan(ref f_IC); dnbInstant.iC = (decimal) f_IC; break; case CommParams.GLYS: //功率因数 byteBlock.Read(out byte[] b_GLYS, 4); base._stringChange.SwapBytes(ref b_GLYS); float f_GLYS = BitConverter.ToSingle(b_GLYS, 0); ValueIsNan(ref f_GLYS); dnbInstant.powerFactor = (decimal) f_GLYS; break; case CommParams.YGGL: //有功功率 byteBlock.Read(out byte[] b_YGGL, 4); base._stringChange.SwapBytes(ref b_YGGL); float f_YGGL = BitConverter.ToSingle(b_YGGL, 0); ValueIsNan(ref f_YGGL); dnbInstant.activePower = Convert.ToDecimal(f_YGGL / 1000); break; case CommParams.WGGL: //无功功率 byteBlock.Read(out byte[] b_WGGL, 4); base._stringChange.SwapBytes(ref b_WGGL); float f_WGGL = BitConverter.ToSingle(b_WGGL, 0); ValueIsNan(ref f_WGGL); dnbInstant.reactivePower = (decimal) f_WGGL; break; case CommParams.ZXYGZ: //正向有功 byteBlock.Read(out byte[] b_ZXYGZ, 4); base._stringChange.SwapBytes(ref b_ZXYGZ); float f_ZXYGZ = BitConverter.ToSingle(b_ZXYGZ, 0); ValueIsNan(ref f_ZXYGZ); dnbInstant.positiveActive = (decimal) f_ZXYGZ; break; case CommParams.CJSJ: //采集时间 byteBlock.Read(out byte[] b_CJSJ, 6); string strDateTime = "20" + b_CJSJ[5].ToString("x2") + "-" + b_CJSJ[4].ToString("x2") + "-" + b_CJSJ[3].ToString("x2") + " " + b_CJSJ[2].ToString("x2") + ":" + b_CJSJ[1].ToString("x2") + ":" + b_CJSJ[0].ToString("x2"); dnbInstant.collectTime = Convert.ToDateTime(strDateTime); break; } } while (byteBlock.Pos % bodyLength != 0); dnbInstant.recordTime = DateTime.Now; var serializeObject = JsonConvert.SerializeObject(dnbInstant); _logger.Info($"第{i+1}个电表{dnbInstant.monitorId}解析完成:{serializeObject}"); DateTime? lastCollectTime = GetLastCollectTime(dnbInstant.monitorId); if (lastCollectTime != null && DateTime.Now -lastCollectTime < TimeSpan.FromMinutes(_appConfig.electricTimeInterval)) { //时间间隔小于采集间隔,不保存 continue; } // 如果字典中已有该键,则更新;否则新增 _lastCollectTimeDict[dnbInstant.monitorId] = DateTime.Now; result.Add(dnbInstant); } if (result.Count > 0) { //是否开启 FF 异常值过滤 if (_appConfig.virtualFlag) { ParamVerification(ref result); } var inRes = _service.SplitInsert(result,out List insertIds); _logger.Info($"{result.Count}个电表数据解析处理完成,数据保存{(inRes ? "成功" : "失败")}"); } else { _logger.Info($"{amount}个电表数据解析处理完成,没有需要保存的数据"); } return FilterResult.Success; } catch (Exception e) { base._logger.Error($"电能数据解析异常:{e.Message}"); } return FilterResult.Cache; } /// /// FF FF参数过滤 /// /// /// private void ParamVerification(ref List dnbInstants) { if (dnbInstants == null) { throw new ArgumentNullException($"过滤参数方法异常,传入参数为空"); } for (int i = dnbInstants.Count - 1; i >= 0; i--) { var item = dnbInstants[i]; if (item.positiveActive == _appConfig.virtualValue) { _logger.Info($"MonitorId:{item.monitorId},正向有功为 FF FF FF FF,已启用过滤不保存该表数据"); dnbInstants.RemoveAt(i); continue; } } } private DateTime? GetLastCollectTime(string key) { // 检查键是否存在 if (_lastCollectTimeDict.TryGetValue(key, out DateTime collectTime)) { return collectTime; } else { return null; } } /// /// 应答处理 /// /// /// public override void ResponseHandle(ISocketClient client, byte[] buffer) { ResponsePack sendResponsePackInfo = new ResponsePack() { m_MessageType = 0xB3 }; base.GetMessagePack(ref sendResponsePackInfo, buffer); base.SendMessageAsync(client,sendResponsePackInfo); } } }