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#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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
{
/// <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);
}
}
}