forked from wenjy/Sln.Iot
1
0
Fork 0
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

299 lines
12 KiB
C#

#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
* (c) 2025 WenJY
* CLR4.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
{
/// <summary>
/// 电能数据
/// </summary>
public class ElectricBusiness:BaseBusiness
{
private Dictionary<string ,DateTime> _lastCollectTimeDict = new Dictionary<string, DateTime>();
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<RecordDnbInstant> result = new List<RecordDnbInstant>();
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<long> insertIds);
_logger.Info($"{result.Count}个电表数据解析处理完成,数据保存{(inRes ? "" : "")}");
}
else
{
_logger.Info($"{amount}个电表数据解析处理完成,没有需要保存的数据");
}
return FilterResult.Success;
}
catch (Exception e)
{
base._logger.Error($"电能数据解析异常:{e.Message}");
}
return FilterResult.Cache;
}
/// <summary>
/// FF FF参数过滤
/// </summary>
/// <param name="dnbInstants"></param>
/// <exception cref="ArgumentNullException"></exception>
private void ParamVerification(ref List<RecordDnbInstant> 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;
}
}
/// <summary>
/// 应答处理
/// </summary>
/// <param name="client"></param>
/// <param name="buffer"></param>
public override void ResponseHandle(ISocketClient client, byte[] buffer)
{
ResponsePack sendResponsePackInfo = new ResponsePack()
{
m_MessageType = 0xB3
};
base.GetMessagePack(ref sendResponsePackInfo, buffer);
base.SendMessageAsync(client,sendResponsePackInfo);
}
}
}