qsp89 52290ac5f7 修改性能状态推送不全问题
遥测数据返回为0,添加调试记录
2025-11-26 15:02:58 +08:00

358 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client;
using Org.BouncyCastle.Utilities;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using YunDa.Server.ISMSTcp.Domain;
using YunDa.Server.ISMSTcp.Interfaces;
namespace YunDa.Server.ISMSTcp.Services
{
public class ZzDataPoint
{
public DateTime TimeStamp { get; set; }
public double Value { get; }
public string ValueStr { get; }
public ZzDataPoint(DateTime time, double value, string valueStr)
{
TimeStamp = time;
Value = value;
ValueStr = valueStr;
}
}
public class ZzData
{
public TimeSpan Retention { get; set; }
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public int? DispatcherAddress { get; set; } = null;
/////////////////////////////////////////////////////////////////////////////////////
public double Value { get; set; }
public string ValueStr { get; set; } = string.Empty;
public DateTime TimeStamp { get; set; }
public uint ValCount { get; set; } = 0;
public DateTime StartTimeStamp { get; set; } = DateTime.MinValue;
/////////////////////////////////////////////////////////////////////////////////////
private readonly ConcurrentQueue<(DateTime time, ZzDataPoint point)> _queue = new ConcurrentQueue<(DateTime time, ZzDataPoint point)>();
public ConcurrentQueue<(DateTime time, ZzDataPoint point)> Datas => _queue;
public ZzData(int minutes, string id, string name, int dispatcherAddress)
{
Retention = TimeSpan.FromMinutes(minutes);
Id = id;
Name = name;
DispatcherAddress = dispatcherAddress;
}
public void AddData(ZzDataPoint point)
{
DateTime now = DateTime.Now;
point.TimeStamp = now; //2025-11-18 用当前时间
_queue.Enqueue((now, point));
TimeStamp = point.TimeStamp;
Value = point.Value;
ValueStr = point.ValueStr;
//////////////////////////////
ValCount++;
if(StartTimeStamp == DateTime.MinValue)
StartTimeStamp = now;
CleanupOldData();
}
private void CleanupOldData()
{
DateTime limit = DateTime.Now - Retention;
while (_queue.TryPeek(out var dp) && dp.time < limit)
{
_queue.TryDequeue(out _);
}
}
public List<ZzDataPoint> GetData(DateTime start, DateTime end)
{
return _queue.Where(dp => dp.point.TimeStamp >= start && dp.point.TimeStamp <= end)
.Select(x => x.point)
.ToList();
}
}
public class ZzDataRequestModel
{
public List<string> Id { get; set; }
public int Times { get; set; }
public int TimeWindowType { get; set; }
}
public class ZzDataResultModel
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string DeviceName { get; set; } = string.Empty;
public int? DispatcherAddress { get; set; } = null;
public double Value { get; set; }
public string ValueStr { get; set; } = string.Empty;
public DateTime TimeStamp { get; set; } = DateTime.MinValue;
public List<ZzDataPoint> Data { get; set; } = new List<ZzDataPoint>();
public ZzDataResultModel()
{
}
public ZzDataResultModel(ZzData data)
{
Id = data.Id;
Name = data.Name;
Value = data.Value;
ValueStr = data.ValueStr;
TimeStamp = data.TimeStamp;
DispatcherAddress = data.DispatcherAddress;
}
}
public class ZzDataHistoryModel
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
}
public enum ZzDataCacheContainerDataType
{
eYC = 0, //遥测
eYX, //遥信
eVA, //虚点
eGW //网关
}
public class ZzDataCacheContainer
{
private readonly ConcurrentDictionary<string, ZzData> _datas = new ConcurrentDictionary<string, ZzData>();
private readonly int _cleanupMinutes = 5;
private ZzDataCacheContainerDataType _dataType = ZzDataCacheContainerDataType.eYC;
private TelemeteringHandle? _telemeteringHandle = null;
public ZzDataCacheContainer(ZzDataCacheContainerDataType dataType, int cleanupMinutes)
{
_dataType = dataType;
_cleanupMinutes = cleanupMinutes;
}
public void SetTelemeteringHandle(TelemeteringHandle handle)
{
_telemeteringHandle = handle;
}
public void Write(string id, double val, DateTime time, string name)
{
var data = _datas.GetOrAdd(id, _ => new ZzData(_cleanupMinutes, id, name, 0));
data.AddData(new ZzDataPoint(time, val, ""));
}
public void Write(string id, double val, DateTime time, string name, string valStr)
{
var data = _datas.GetOrAdd(id, _ => new ZzData(_cleanupMinutes, id, name, 0));
data.AddData(new ZzDataPoint(time, val, valStr));
}
public void Write(string id, double val, DateTime time, string name, string valStr, int dispatcherAddress)
{
//if (id == "YCB001101001")
//{
// int kk = 0;
//}
var data = _datas.GetOrAdd(id, _ => new ZzData(_cleanupMinutes, id, name, dispatcherAddress));
data.AddData(new ZzDataPoint(time, val, valStr));
}
public async Task<Dictionary<string, ZzDataResultModel>> Read(List<string> ids, DateTime start, DateTime end)
{
var result = new Dictionary<string, ZzDataResultModel>();
foreach (var id in ids)
{
//if (id == "YCB001101001")
//{
// int kk = 0;
//}
if (_datas.TryGetValue(id, out var channel))
{
ZzDataResultModel data = new ZzDataResultModel(channel);
data.Data = channel.GetData(start, end);
bool isFind = data.Data.Count > 0;
if (data.Data.Count == 0 && data.TimeStamp != DateTime.MinValue)
{
ZzDataPoint zzDataPoint = new ZzDataPoint(DateTime.Now, data.Value, data.ValueStr.Replace(" ", ""));
data.Data.Add(zzDataPoint);
}
if (_telemeteringHandle != null &&_dataType == ZzDataCacheContainerDataType.eYC && id == "YCB001103003")
{
if (data.Data.Where(e => Math.Abs(e.Value) < 0.0001).Count() == data.Data.Count)
{
string time = DateTime.Now.ToString("yyy/MM/dd HH:mm:ss");
_telemeteringHandle.LogWarning($"【{time}】: {id}所有值为0[{data.Data.Count}]:状态:{isFind} Cache长度{channel.Datas.Count}, Cache时间{channel.StartTimeStamp.ToString("yyy/MM/dd HH:mm:ss")} ~ {channel.TimeStamp.ToString("yyy/MM/dd HH:mm:ss")}, 最后一个值:{channel.ValueStr}");
var redisData = await _telemeteringHandle.GetDataFromRedis(id);
if (redisData != null)
{
_telemeteringHandle.LogWarning($"【{time}】: {id}在Redis中的值为{redisData.ResultValue} - {redisData.ResultTime }");
}
else
{
_telemeteringHandle.LogWarning($"【{time}】: {id}在Redis中没有找到");
}
}
}
result[id] = data;
}
}
return result;
}
public async Task<List<ZzDataResultModel>> Read(List<string> ids, int seconds, int timeWindowType, CancellationToken cancellationToken, DateTime now = default)
{
try
{
if(now == default)
now = DateTime.Now;
//寻找匹配的值
Dictionary<string, ZzDataResultModel> matched1 = new Dictionary<string, ZzDataResultModel>();
Dictionary<string, ZzDataResultModel> matched2 = new Dictionary<string, ZzDataResultModel>();
if (timeWindowType == 0 || timeWindowType == 2)
{
matched1 = await Read(ids, now.AddSeconds(-seconds), now);
}
if (timeWindowType == 1 || timeWindowType == 2)
{
int span = seconds*1000 - (int)(DateTime.Now - now).TotalMilliseconds;
if(span > 0)
await Task.Delay(span, cancellationToken);
matched2 = await Read(ids, now, DateTime.Now);
}
foreach (var kv in matched2)
{
if (!matched1.TryAdd(kv.Key, kv.Value))
{
matched1[kv.Key].Data.AddRange(kv.Value.Data);
}
}
return matched1.Values.ToList();
}
catch (Exception ex)
{
return new List<ZzDataResultModel>();
}
}
}
public class ZzDataCacheContainerInit
{
private readonly ILogger<SecondaryCircuitInspectionPlanService> _logger;
private readonly WebApiRequest _webApiRequest;
private readonly ZzTcpService _zTcpService = null;
public ZzDataCacheContainerInit(ILogger<SecondaryCircuitInspectionPlanService> logger, WebApiRequest webApiRequest, ZzTcpService zTcpService)
{
_logger = logger;
_webApiRequest = webApiRequest;
_zTcpService = zTcpService;
}
public void InitTcpService(ITcpClient tcpClient)
{
_zTcpService.Init(tcpClient);
}
//初始化虚点信息
public async Task InitVariantBaseinfo(ZzDataCacheContainer cache)
{
//从数据库获取
var list = await _webApiRequest.GetVariantBaseinfoAsync();
if (list != null)
{
foreach (var item in list)
{
cache.Write(item.Id, 2, DateTime.Now, item.Name, "不定");
}
}
//发送命令从综自获取
if(_zTcpService != null)
{
string cmd = "CallVAByStat|B001";
for (int i = 0; i < 5; i++)
{
var sendResult = await _zTcpService.SendTcpMessageAsync(cmd, CancellationToken.None);
if (sendResult.Success)
{
break;
}
await Task.Delay(2000);
}
}
}
//初始化网关信息
public async Task InitGateWayBaseInfo(ZzDataCacheContainer cache)
{
var list = await _webApiRequest.GetGateWayBaseInfoAsync();
if (list != null)
{
foreach (var item in list)
{
cache.Write(item.Id, 0, DateTime.Now, item.Name, "0.00 %");
}
}
}
}
}