2325 lines
102 KiB
C#
2325 lines
102 KiB
C#
using JinYuan.Helper;
|
||||
|
|
using JinYuan.MES.Models;
|
|||
|
|
using JinYuan.Models;
|
|||
|
|
using JinYuan.VirtualDataLibrary;
|
|||
|
|
using Language;
|
|||
|
|
using MiniExcelLibs;
|
|||
|
|
using PLC;
|
|||
|
|
using PLC.PLCAlarm;
|
|||
|
|
using PLCCommunication;
|
|||
|
|
using PLCCommunication.Common;
|
|||
|
|
using PLCCommunication.Common.DataConvert;
|
|||
|
|
using SqlSugar;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Concurrent;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Diagnostics;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Net;
|
|||
|
|
using System.Net.NetworkInformation;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
using System.Windows.Forms;
|
|||
|
|
using DataType = PLC.DataType;
|
|||
|
|
|
|||
|
|
|
|||
|
|
namespace JinYuan.ControlCenters
|
|||
|
|
{
|
|||
|
|
public partial class ControlCenter : IDisposable
|
|||
|
|
{
|
|||
|
|
private static readonly object uiLock = new object();
|
|||
|
|
private static ControlCenter _instance;
|
|||
|
|
public static ControlCenter Instance
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
lock (uiLock)
|
|||
|
|
{
|
|||
|
|
return _instance ??= new ControlCenter();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private readonly Dictionary<string, PlcGroup> groups = new Dictionary<string, PlcGroup>();
|
|||
|
|
private Dictionary<string, Func<JYResult<byte[]>, PlcGroup, Task>> stationFunctions;
|
|||
|
|
//private Dictionary<string, Action<JYResult<byte[]>, PlcGroup>> stationFunctions;
|
|||
|
|
private readonly Dictionary<PlcReadWriteBase, List<PlcDevice>> plcDeviceMapping = new Dictionary<PlcReadWriteBase, List<PlcDevice>>();
|
|||
|
|
private readonly Dictionary<string, Task> groupTasks = new Dictionary<string, Task>();
|
|||
|
|
private readonly Dictionary<PlcReadWriteBase, PLCAlarmReader> plcAlarmReaders = new Dictionary<PlcReadWriteBase, PLCAlarmReader>();
|
|||
|
|
private readonly ConcurrentDictionary<string, short> _lastOpenValues = new ConcurrentDictionary<string, short>();
|
|||
|
|
|
|||
|
|
public CancellationTokenSource _cts;
|
|||
|
|
private Task _heartbeatTask;
|
|||
|
|
private const int HeartbeatInterval = 1000; // 1 second
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 定时器-定时刷新状态和数据
|
|||
|
|
/// </summary>
|
|||
|
|
private System.Timers.Timer Timer_RefreshData;
|
|||
|
|
|
|||
|
|
private readonly string configFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config");
|
|||
|
|
|
|||
|
|
private ControlCenter()
|
|||
|
|
{
|
|||
|
|
_cts = new CancellationTokenSource();
|
|||
|
|
|
|||
|
|
if (CommonMethods.plcDevices == null)
|
|||
|
|
{
|
|||
|
|
CommonMethods.plcDevices = new List<PlcReadWriteBase>();
|
|||
|
|
}
|
|||
|
|
InitializeDevicesFromExcel();
|
|||
|
|
GetAlarmData();
|
|||
|
|
InitFunc();
|
|||
|
|
|
|||
|
|
Timer_RefreshData = new System.Timers.Timer(1000);
|
|||
|
|
Timer_RefreshData.Elapsed += Timer_RefreshData_Elapsed;
|
|||
|
|
Timer_RefreshData.Start();
|
|||
|
|
|
|||
|
|
Thread thread = new Thread(ShowStateEven_Run);
|
|||
|
|
thread.IsBackground = true;
|
|||
|
|
thread.Start();
|
|||
|
|
|
|||
|
|
// 轴位置监控
|
|||
|
|
Task.Run(() => { ShowAxleEven_Run(); });
|
|||
|
|
|
|||
|
|
// 电机位置监控
|
|||
|
|
//Task.Run(() => { ShowMotorEven_Run(); });
|
|||
|
|
|
|||
|
|
//Mes心跳监控
|
|||
|
|
Task.Run(new Action(() => { UpdateMesHeartBeat(); }));
|
|||
|
|
|
|||
|
|
//删除30天内日志
|
|||
|
|
//DeleteLog.Start(CommonMethods.strDeletepath);//会把整个ApiLog删除
|
|||
|
|
string[] clrPath = new string[] { CommonMethods.strAlarmLogspath, CommonMethods.strMesLogspath, CommonMethods.strWattrMeterpath, @"D:\Logs\" };
|
|||
|
|
short[] seltWay = new short[] { 0, 0, 0, 1 };
|
|||
|
|
DeleteLog.Start(clrPath, seltWay);
|
|||
|
|
|
|||
|
|
if (!CommonMethods.IsRun)
|
|||
|
|
{
|
|||
|
|
CommonMethods.ResetEventRecv.Reset();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 初始化 工位方法,添加到字典里面
|
|||
|
|
/// </summary>
|
|||
|
|
private void InitFunc()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
stationFunctions = new Dictionary<string, Func<JYResult<byte[]>, PlcGroup, Task>>
|
|||
|
|
{
|
|||
|
|
["电芯进站A"] = FeedingStationA,
|
|||
|
|
//["电芯进站B"] = FeedingStationB,
|
|||
|
|
["电芯出站A"] = BlankingStationA,
|
|||
|
|
["电芯出站B"] = BlankingStationB,
|
|||
|
|
["电芯出站C"] = BlankingStationC,
|
|||
|
|
//["结构件料盘"] = MaterialStation,
|
|||
|
|
// 根据需要添加更多站点功能
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public async Task StartAsync()
|
|||
|
|
{
|
|||
|
|
CreatePLCThreads();
|
|||
|
|
_heartbeatTask = StartHeartbeatCheck(_cts.Token);
|
|||
|
|
await Task.CompletedTask;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region PLC
|
|||
|
|
private void InitializeDevicesFromExcel()
|
|||
|
|
{
|
|||
|
|
CommonMethods.AddDataMonitorLog(1, "开始加载配置参数……".Translated());
|
|||
|
|
string deviceConfigPath = Path.Combine(configFolderPath, "Device.xlsx");
|
|||
|
|
string groupConfigPath = Path.Combine(configFolderPath, "Group.xlsx");
|
|||
|
|
string variableConfigPath = Path.Combine(configFolderPath, "Variable.xlsx");
|
|||
|
|
string plcVariableConfigPath = Path.Combine(configFolderPath, "PLCVariable.xlsx");
|
|||
|
|
|
|||
|
|
if (!File.Exists(deviceConfigPath) || !File.Exists(groupConfigPath) || !File.Exists(variableConfigPath))
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError("配置文件不存在");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var deviceConfigs = MiniExcel.Query<PlcDevice>(deviceConfigPath).ToList();
|
|||
|
|
var groupConfigs = MiniExcel.Query<PlcGroup>(groupConfigPath).ToList();
|
|||
|
|
var variableConfigs = MiniExcel.Query<PlcVariable>(variableConfigPath).ToList();
|
|||
|
|
|
|||
|
|
var plcVariableConfigs = MiniExcel.Query<PLCGroupVariable>(plcVariableConfigPath).ToList();
|
|||
|
|
ConcurrentDictionary<string, PLCGroupVariable> PLCVariable = new ConcurrentDictionary<string, PLCGroupVariable>();
|
|||
|
|
if (plcVariableConfigs.Count > 0)
|
|||
|
|
{
|
|||
|
|
foreach (PLCGroupVariable variable in plcVariableConfigs)
|
|||
|
|
{
|
|||
|
|
if (variable.VarAddress != null && !variable.VarAddress.Equals(""))
|
|||
|
|
{
|
|||
|
|
PLCVariable.TryAdd(variable.VarAddress.Trim(), variable);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
CommonMethods.PLCVariable = PLCVariable;
|
|||
|
|
|
|||
|
|
foreach (var deviceConfig in deviceConfigs.Where(d => d.IsActive))
|
|||
|
|
{
|
|||
|
|
IPEndPoint iep = new IPEndPoint(IPAddress.Parse(deviceConfig.IPAddress), deviceConfig.Port);
|
|||
|
|
PlcReadWriteBase plc = PLCFactory.CreatePLC(GetPLCTypeEnum(deviceConfig.PLCType), deviceConfig.PlcNum, $"PLC_{deviceConfig.PlcNum}", iep);
|
|||
|
|
|
|||
|
|
deviceConfig.Cts = new CancellationTokenSource();
|
|||
|
|
deviceConfig.GroupList = groupConfigs
|
|||
|
|
.Where(g => g.IsActive && g.PlcNum == deviceConfig.PlcNum)
|
|||
|
|
.ToList();
|
|||
|
|
|
|||
|
|
foreach (var group in deviceConfig.GroupList)
|
|||
|
|
{
|
|||
|
|
group.VarList = variableConfigs
|
|||
|
|
.Where(v => v.GroupName == group.GroupName && v.PlcNum == deviceConfig.PlcNum)
|
|||
|
|
.ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
plcDeviceMapping[plc] = new List<PlcDevice> { deviceConfig };
|
|||
|
|
CommonMethods.plcDevices.Add(plc);
|
|||
|
|
|
|||
|
|
string tmp = AppDomain.CurrentDomain.BaseDirectory;
|
|||
|
|
|
|||
|
|
// 初始化 PLCAlarm Reader报警读取
|
|||
|
|
var alarmReader = new PLCAlarmReader(
|
|||
|
|
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlarmConfig.csv"),
|
|||
|
|
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AlarmRecords"),
|
|||
|
|
RecordType.RecordWhenFinish,
|
|||
|
|
false
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
//alarmReader.PLCAlarm_New += AlrmReader_PLCAlarm_New;
|
|||
|
|
//alarmReader.PLCAlarm_Remove += AlrmReader_PLCAlarm_Remove;
|
|||
|
|
//plcAlarmReaders[plc] = alarmReader;
|
|||
|
|
|
|||
|
|
//CommonMethods.plcStatuses[plc] = new Dictionary<string, object>
|
|||
|
|
//{
|
|||
|
|
// ["OldStatus"] = (short)0,
|
|||
|
|
// ["StatusCount"] = 0,
|
|||
|
|
// ["GuidAlarm"] = string.Empty,
|
|||
|
|
// ["Status"] = new List<bool> { false, false, false, false }
|
|||
|
|
//};
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"加载配置失败:{ex.Message}");
|
|||
|
|
}
|
|||
|
|
CommonMethods.AddDataMonitorLog(1, "配置文件加载完成".Translated());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region 创建PLC线程 几个工位就几个线程
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 按工位读取线程
|
|||
|
|
/// </summary>
|
|||
|
|
///
|
|||
|
|
|
|||
|
|
private readonly Dictionary<string, Thread> groupThreads = new Dictionary<string, Thread>();
|
|||
|
|
private readonly object lockObject = new object();
|
|||
|
|
|
|||
|
|
private void CreatePLCThreads()
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < CommonMethods.plcDevices.Count; i++)
|
|||
|
|
{
|
|||
|
|
var plc = CommonMethods.plcDevices[i];
|
|||
|
|
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
|
|||
|
|
{
|
|||
|
|
foreach (var plcDevice in plcDevices)
|
|||
|
|
{
|
|||
|
|
foreach (var plcGroup in plcDevice.GroupList.Where(g => g.IsActive))
|
|||
|
|
{
|
|||
|
|
string threadKey = $"{plcDevice.PlcNum}-{plcGroup.GroupName}";
|
|||
|
|
|
|||
|
|
var parameter = (group: plcGroup, plcIndex: i);
|
|||
|
|
|
|||
|
|
Thread thread = new Thread(new ParameterizedThreadStart(ReadPLCWorkModel));
|
|||
|
|
thread.IsBackground = true;
|
|||
|
|
thread.Priority = ThreadPriority.Highest;
|
|||
|
|
lock (lockObject)
|
|||
|
|
{
|
|||
|
|
groupThreads[threadKey] = thread;
|
|||
|
|
}
|
|||
|
|
thread.Start(parameter);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 循环读取PLC工位状态
|
|||
|
|
/// <summary>
|
|||
|
|
/// 读取PLC循环工位
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="plcModel"></param>
|
|||
|
|
private void ReadPLCWorkModel(object parameter)
|
|||
|
|
{
|
|||
|
|
if (parameter is ValueTuple<PlcGroup, int> tuple)
|
|||
|
|
{
|
|||
|
|
var sw = new Stopwatch();
|
|||
|
|
var (group, plcIndex) = tuple;
|
|||
|
|
string groupKey = group.GroupName;
|
|||
|
|
|
|||
|
|
while (!_cts.Token.IsCancellationRequested)
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.IsRun)
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.plcDevices[plcIndex].IsConnected)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
JYResult<short> OpenValue = CommonMethods.plcDevices[plcIndex].ReadValue<JYResult<short>>(group.VarList[0].VarAddress, DataType.Short);
|
|||
|
|
|
|||
|
|
// 获取上一次的值,如果不存在则默认为0
|
|||
|
|
short lastValue = _lastOpenValues.GetOrAdd(groupKey, 0);
|
|||
|
|
|
|||
|
|
// 从0到1才执行
|
|||
|
|
if (OpenValue.IsSuccess && OpenValue.Content == 1 && lastValue == 0)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteLog($"[{groupKey}] 检测到上升沿(0->1),开始处理", "PLC线程");
|
|||
|
|
// 更新上一次的值
|
|||
|
|
_lastOpenValues[groupKey] = 1;
|
|||
|
|
|
|||
|
|
sw.Restart();
|
|||
|
|
bool bRet = CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)2);
|
|||
|
|
sw.Stop();
|
|||
|
|
LogHelper.Instance.WriteLog($"[{groupKey}] 往{group.VarList[0].VarAddress}写2,写入结果:{bRet},耗时:{sw.ElapsedMilliseconds}ms","PLC线程");
|
|||
|
|
|
|||
|
|
if (!bRet)
|
|||
|
|
{
|
|||
|
|
bRet = CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)2);
|
|||
|
|
LogHelper.Instance.WriteLog($"重试:往{group.VarList[0].VarAddress}写2,写入结果:{bRet}", "PLC线程");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
sw.Restart();
|
|||
|
|
JYResult<byte[]> resByte = CommonMethods.plcDevices[plcIndex].ReadValue<JYResult<byte[]>>($"{group.VarList[2].VarAddress}",
|
|||
|
|
DataType.ArrByte, Convert.ToUInt16(group.VarList[2].OffsetOrLength));
|
|||
|
|
sw.Stop();
|
|||
|
|
LogHelper.Instance.WriteLog($"[{groupKey}] 读取数据区 {group.VarList[2].VarAddress}, " + $"长度={group.VarList[2].OffsetOrLength}, 成功={resByte?.IsSuccess},耗时:{sw.ElapsedMilliseconds}","PLC线程");
|
|||
|
|
|
|||
|
|
|
|||
|
|
if (resByte != null && stationFunctions.TryGetValue(group.GroupName, out var action))
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteLog($"[{groupKey}] 开始执行工位逻辑", "PLC线程");
|
|||
|
|
sw.Restart();
|
|||
|
|
Task.Run(() => action(resByte, group));
|
|||
|
|
sw.Stop();
|
|||
|
|
LogHelper.Instance.WriteLog($"[{groupKey}] 工位逻辑执行完成,耗时:{sw.ElapsedMilliseconds}ms", "PLC线程");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
bool bRet2 = CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)2);
|
|||
|
|
|
|||
|
|
LogHelper.Instance.WriteLog($"异常情况,resByte={resByte}为空或者{group.GroupName}找不到执行函数,往{group.VarList[0].VarAddress}写0,写入结果:{bRet2}", "PLC线程");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (OpenValue.IsSuccess && OpenValue.Content == 0)
|
|||
|
|
{
|
|||
|
|
// 当值变为0时,更新记录,以便下次0->1时触发
|
|||
|
|
_lastOpenValues[groupKey] = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"错误: {group.GroupName} - {ex.Message}", "SysErrorLog");
|
|||
|
|
var bRet = CommonMethods.plcDevices[plcIndex].WriteInt16(group.VarList[0].VarAddress, (short)0);
|
|||
|
|
LogHelper.Instance.WriteLog($"异常场景下,往{group.VarList[0].VarAddress}写0,写入是否成功:{bRet}", "PLC线程");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
Thread.Sleep(100);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 开始停止联机事件
|
|||
|
|
/// <summary>
|
|||
|
|
/// 开始联机
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
|
|||
|
|
public async Task<bool> ConnectAllPlcsAsync()
|
|||
|
|
{
|
|||
|
|
bool allConnected = true;
|
|||
|
|
if (CommonMethods.plcDevices.Count <= 0)
|
|||
|
|
{
|
|||
|
|
CommonMethods.AddDataMonitorLog(1, "无PLC配置信息".Translated() + "," + "请检查配置文件".Translated());
|
|||
|
|
return allConnected = false;
|
|||
|
|
}
|
|||
|
|
foreach (var plc in CommonMethods.plcDevices)
|
|||
|
|
{
|
|||
|
|
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
|
|||
|
|
{
|
|||
|
|
foreach (var deviceConfig in plcDevices)
|
|||
|
|
{
|
|||
|
|
string msg = "";
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 使用 Task.Run 来在后台线程执行连接操作
|
|||
|
|
bool isConnected = await Task.Run(() =>
|
|||
|
|
{
|
|||
|
|
// 设置一个连接超时
|
|||
|
|
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))) // 10秒超时
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
return plc.Connect(ref msg);
|
|||
|
|
}
|
|||
|
|
catch (OperationCanceledException)
|
|||
|
|
{
|
|||
|
|
msg = "连接超时";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
deviceConfig.IsConnected = isConnected;
|
|||
|
|
|
|||
|
|
if (!deviceConfig.IsConnected)
|
|||
|
|
{
|
|||
|
|
allConnected = false;
|
|||
|
|
LogHelper.Instance.WriteLog($"连接PLC失败: {deviceConfig.PlcNum}, 错误: {msg}");
|
|||
|
|
CommonMethods.AddDataMonitorLog(1, "连接PLC失败".Translated() + $": {deviceConfig.PlcNum}, " + "错误".Translated() + $": {msg}");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, "成功连接PLC".Translated() + $": {deviceConfig.PlcNum}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
allConnected = false;
|
|||
|
|
LogHelper.Instance.WriteLog($"连接PLC时发生异常: {deviceConfig.PlcNum}, 错误: {ex.Message}");
|
|||
|
|
CommonMethods.AddDataMonitorLog(2, "连接PLC时发生异常".Translated() + $": {deviceConfig.PlcNum}" + "错误".Translated() + $": {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return allConnected;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 断开链接
|
|||
|
|
/// </summary>
|
|||
|
|
public void DisconnectAllPlcs()
|
|||
|
|
{
|
|||
|
|
foreach (var plc in CommonMethods.plcDevices)
|
|||
|
|
{
|
|||
|
|
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
|
|||
|
|
{
|
|||
|
|
foreach (var deviceConfig in plcDevices)
|
|||
|
|
{
|
|||
|
|
plc.Disconnect();
|
|||
|
|
deviceConfig.IsConnected = false;
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, "已断开与PLC".Translated() + $"[{deviceConfig.PlcNum}]" + "的链接".Translated());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region MES
|
|||
|
|
/// <summary>
|
|||
|
|
/// Mes心跳
|
|||
|
|
/// </summary>
|
|||
|
|
private void UpdateMesHeartBeat()
|
|||
|
|
{
|
|||
|
|
Thread.Sleep(100);
|
|||
|
|
while (true)//true
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.mesConfig.IsLoginMesOK && CommonMethods.IsRun)//CommonMethods.mesConfig.isUpMes &&
|
|||
|
|
{
|
|||
|
|
if (Ping() == true)
|
|||
|
|
{
|
|||
|
|
CommonMethods.mesConfig.isConnected = true;
|
|||
|
|
string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping成功,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort}";
|
|||
|
|
TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
|
|||
|
|
}
|
|||
|
|
else//Ping失败,提示检查线路。
|
|||
|
|
{
|
|||
|
|
int count = 0;
|
|||
|
|
bool mesOnLine = false;
|
|||
|
|
do//重复3次
|
|||
|
|
{
|
|||
|
|
Thread.Sleep(1000);
|
|||
|
|
if (Ping() == true) { mesOnLine = true; break; }
|
|||
|
|
count++;
|
|||
|
|
}
|
|||
|
|
while (count < 3);
|
|||
|
|
|
|||
|
|
if (!mesOnLine)
|
|||
|
|
{
|
|||
|
|
CommonMethods.mesConfig.isConnected = false;
|
|||
|
|
CommonMethods.plcDevices[0].WriteInt16("D80", (short)1);
|
|||
|
|
|
|||
|
|
string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping失败,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort}";
|
|||
|
|
TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping异常,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort},原因:{ex.ToString()}";
|
|||
|
|
TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
|
|||
|
|
}
|
|||
|
|
Thread.Sleep(1000);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Ping 检查网络线路问题
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
public bool Ping()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
string strIP = CommonMethods.mesConfig.MESURLAddressIP;
|
|||
|
|
int port = Convert.ToInt32(CommonMethods.mesConfig.MESURLAddressPort);
|
|||
|
|
IPAddress ip = IPAddress.Parse(strIP);
|
|||
|
|
IPEndPoint _endPoint = new IPEndPoint(ip, port);
|
|||
|
|
|
|||
|
|
if (_endPoint.Address == null)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Ping _ping = new Ping();
|
|||
|
|
int timeout = 1000;
|
|||
|
|
PingReply mPingRcv = _ping.Send(_endPoint.Address, timeout);
|
|||
|
|
return (mPingRcv.Status == IPStatus.Success) ? true : false;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
string errStr = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")},Mes心跳Ping异常,IP:{CommonMethods.mesConfig.MESURLAddressIP},端口号:{CommonMethods.mesConfig.MESURLAddressPort},原因:{ex.ToString()}";
|
|||
|
|
TxtHelper.WriteTxt($@"D:\APILog\Logs\MesLogs\{DateTime.Now.ToString("yyyyMMdd")}\Mes心跳报警\{DateTime.Now.ToString("HH")}.txt", errStr);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 4、心跳和状态检查
|
|||
|
|
/// <summary>
|
|||
|
|
/// 心跳检测
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="cancellationToken"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private async Task StartHeartbeatCheck(CancellationToken cancellationToken)
|
|||
|
|
{
|
|||
|
|
while (!cancellationToken.IsCancellationRequested)
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.IsRun)
|
|||
|
|
{
|
|||
|
|
foreach (var plc in CommonMethods.plcDevices)
|
|||
|
|
{
|
|||
|
|
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
|
|||
|
|
{
|
|||
|
|
foreach (var plcDevice in plcDevices)
|
|||
|
|
{
|
|||
|
|
if (plcDevice.IsActive && plcDevice.IsHeartBeat)
|
|||
|
|
{
|
|||
|
|
await CheckHeartbeatForDevice(plc, plcDevice);
|
|||
|
|
//await ShowStateEven_RunAsync();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
await Task.Delay(HeartbeatInterval, cancellationToken);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="plc"></param>
|
|||
|
|
/// <param name="plcDevice"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private async Task CheckHeartbeatForDevice(PlcReadWriteBase plc, PlcDevice plcDevice)
|
|||
|
|
{
|
|||
|
|
if (plcDevice.IsConnected)
|
|||
|
|
{
|
|||
|
|
JYResult result;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
result = await Task.Run(() => plc.ReadValue<JYResult<short>>(plcDevice.HeartBeat, DataType.Short));
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
plcDevice.ErrorTimes++;
|
|||
|
|
plcDevice.IsConnected = false;
|
|||
|
|
LogHelper.Instance.WriteLog($"PLC编号:{plcDevice.PlcNum} 读取心跳异常:{ex.Message}!!!");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (result.IsSuccess)
|
|||
|
|
{
|
|||
|
|
plcDevice.ErrorTimes = 0;
|
|||
|
|
JYResult res;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
res = await Task.Run(() => plc.WriteValue(plcDevice.HeartBeat, (short)1, DataType.Short));
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
plcDevice.IsConnected = false;
|
|||
|
|
LogHelper.Instance.WriteError($"PLC编号:{plcDevice.PlcNum} 写入心跳异常:{ex.Message}!!!");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!res.IsSuccess)
|
|||
|
|
{
|
|||
|
|
plcDevice.IsConnected = false;
|
|||
|
|
LogHelper.Instance.WriteError($"PLC编号:{plcDevice.PlcNum}=心跳写入异常:{res.Message}!!!");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
HandleHeartbeatFailure(plcDevice, result);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
await ReconnectDevice(plc, plcDevice);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void HandleHeartbeatFailure(PlcDevice plcDevice, JYResult result)
|
|||
|
|
{
|
|||
|
|
plcDevice.ErrorTimes++;
|
|||
|
|
plcDevice.IsConnected = false;
|
|||
|
|
if (plcDevice.ErrorTimes >= plcDevice.AllowErrorTimes)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"编号:[{plcDevice.PlcNum}]的PLC链接断开:{result.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private async Task ReconnectDevice(PlcReadWriteBase plc, PlcDevice plcDevice)
|
|||
|
|
{
|
|||
|
|
if (!plcDevice.IsFirstConnect)
|
|||
|
|
{
|
|||
|
|
await Task.Delay(plcDevice.ReConnectTime);
|
|||
|
|
try { plc.Disconnect(); }
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"编号:[{plcDevice.PlcNum}]的PLC断开链接异常:{ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
string msg = "";
|
|||
|
|
bool connectResult = false;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
connectResult = await Task.Run(() => plc.Connect(ref msg));
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
msg = ex.Message;
|
|||
|
|
connectResult = false;
|
|||
|
|
}
|
|||
|
|
plcDevice.IsConnected = connectResult;
|
|||
|
|
LogHelper.Instance.WriteError(connectResult
|
|||
|
|
? $"PLC编号:{plcDevice.PlcNum}{(plcDevice.IsFirstConnect ? "初次" : "重新")}连接成功{msg}!"
|
|||
|
|
: $"[{plcDevice.PlcNum}]#PLC{(plcDevice.IsFirstConnect ? "初次" : "重新")}连接失败{msg}!");
|
|||
|
|
|
|||
|
|
plcDevice.IsFirstConnect = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 定时刷新数据
|
|||
|
|
|
|||
|
|
int TotalNum = 0;
|
|||
|
|
int TotalNum1 = 0;
|
|||
|
|
int Regular = 0;
|
|||
|
|
int jetBeat = 0;
|
|||
|
|
private void Timer_RefreshData_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
|||
|
|
{
|
|||
|
|
if (Regular >= 300)
|
|||
|
|
{
|
|||
|
|
Task.Run(() =>
|
|||
|
|
{
|
|||
|
|
GetEnergyDataFormSerialPort();
|
|||
|
|
UploadEquEnergy();
|
|||
|
|
});
|
|||
|
|
Regular = 0;
|
|||
|
|
}
|
|||
|
|
if (TotalNum > 4)
|
|||
|
|
{
|
|||
|
|
//GetEnergyDataFormSerialPort();
|
|||
|
|
Refresh12HourProdQty();
|
|||
|
|
GetDefectTypeQty();
|
|||
|
|
ReadPLCComm();
|
|||
|
|
|
|||
|
|
GetASqlAlarmData(DateTime.Today, CommonMethods.strClass);
|
|||
|
|
TotalNum = 0;
|
|||
|
|
}
|
|||
|
|
else if (TotalNum == 2)//设备状态读取
|
|||
|
|
{
|
|||
|
|
SetClass(); //变更班次
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//Task.Run(() =>
|
|||
|
|
//{
|
|||
|
|
// ShowStateEven_Run();
|
|||
|
|
//});
|
|||
|
|
|
|||
|
|
if (TotalNum1 >= 3600 * 24)
|
|||
|
|
{
|
|||
|
|
Task.Run(() =>
|
|||
|
|
{
|
|||
|
|
DeleteFileOfLocal();
|
|||
|
|
});
|
|||
|
|
TotalNum1 = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//电能表心跳
|
|||
|
|
//if (jetBeat > 3)
|
|||
|
|
//{
|
|||
|
|
//if (CommonMethods.jetClientA.Connect()) { CommonMethods.jetClientA.connectState = true; }
|
|||
|
|
//else { CommonMethods.jetClientA.connectState = false; }
|
|||
|
|
//if (CommonMethods.jetClientB.Connect()) { CommonMethods.jetClientB.connectState = true; }
|
|||
|
|
//else { CommonMethods.jetClientB.connectState = false; }
|
|||
|
|
//if (!CommonMethods.energyMeter.Connected) { CommonMethods.energyMeter.Connect(); }
|
|||
|
|
//jetBeat = 0;
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
//jetBeat++;
|
|||
|
|
TotalNum++;
|
|||
|
|
TotalNum1++;
|
|||
|
|
Regular++;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 设备综合信息
|
|||
|
|
/// <summary>
|
|||
|
|
/// 读取PLC通用信息
|
|||
|
|
/// </summary>
|
|||
|
|
internal void ReadPLCComm()
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.plcDevices.Count != 0 && CommonMethods.plcDevices[0].IsConnected)
|
|||
|
|
{
|
|||
|
|
Task.Run(async () =>
|
|||
|
|
{
|
|||
|
|
await UpTotalCount(null);
|
|||
|
|
Thread.Sleep(50);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
CommonMethods.TotalQty = Convert.ToInt32(CommonMethods.plcDevices[0].ReadFloat("D15"));//CommonMethods.plcDevices[0].ReadInt32("D15");//生产总数
|
|||
|
|
CommonMethods.ProOKQty = Convert.ToInt32(CommonMethods.plcDevices[0].ReadFloat("D17"));//CommonMethods.plcDevices[0].ReadInt32("D17");//良品总数
|
|||
|
|
|
|||
|
|
CommonMethods.Ppm = Convert.ToInt32(CommonMethods.plcDevices[0].ReadFloat("D13")); //PPM
|
|||
|
|
CommonMethods.JiaDL = Convert.ToDouble(CommonMethods.plcDevices[0].ReadFloat("D11").ToString("F2"));//稼动率
|
|||
|
|
|
|||
|
|
#region 开机时间/运行时间
|
|||
|
|
CommonMethods.PlcOpenAndRunTime = GetList<int>(6, 0);
|
|||
|
|
JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"D50", DataType.ArrByte, 12);
|
|||
|
|
if (resByte.IsSuccess && resByte.Content.Length >= 24)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < CommonMethods.PlcOpenAndRunTimeAdress.Count; i++)
|
|||
|
|
{
|
|||
|
|
CommonMethods.PlcOpenAndRunTime[i] = ShortLib.GetShortFromByteArray(resByte.Content, i * 4, DataFormat.CDAB);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 保存12小时产能数据
|
|||
|
|
public int totalNum = 0; // 总数
|
|||
|
|
public int okNum = 0; // 良品数
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 储存数据到数据库
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="DataCount"></param>
|
|||
|
|
public async Task UpTotalCount(int[] DataCount)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
DateTime dateTime = DateTime.Now;
|
|||
|
|
string strDate = dateTime.ToString("yyyy-MM-dd");
|
|||
|
|
|
|||
|
|
// 获取当前时间的小时和分钟
|
|||
|
|
int currentHour = dateTime.Hour;
|
|||
|
|
int currentMinute = dateTime.Minute;
|
|||
|
|
|
|||
|
|
// 根据当前分钟确定统计小时
|
|||
|
|
// 如果当前时间在 X:30 之前,则统计的是前一个小时的数据(从前一个小时的30分到这个小时的29分)
|
|||
|
|
// 如果当前时间在 X:30 之后,则统计的是当前小时的数据(从当前小时的30分到下个小时的29分)
|
|||
|
|
int statisticalHour;
|
|||
|
|
if (currentMinute < 30)
|
|||
|
|
{
|
|||
|
|
statisticalHour = (currentHour + 23) % 24; // 前一个小时,处理跨天的情况
|
|||
|
|
// 如果是凌晨0点前的数据,需要使用前一天的日期
|
|||
|
|
if (currentHour == 0)
|
|||
|
|
{
|
|||
|
|
strDate = dateTime.AddDays(-1).ToString("yyyy-MM-dd");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
statisticalHour = currentHour;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 数据有效性验证
|
|||
|
|
if (statisticalHour < 0 || statisticalHour > 23)
|
|||
|
|
{
|
|||
|
|
throw new ArgumentException($"无效的小时值: {statisticalHour}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//读取统计小时的PLC投入总数和产出数
|
|||
|
|
int ProdCurrAllQty = GetToDayHourQty(statisticalHour, true);
|
|||
|
|
int ProdCurrOKQty = GetToDayHourQty(statisticalHour, false);
|
|||
|
|
|
|||
|
|
// 确保数量为非负数
|
|||
|
|
if (ProdCurrAllQty < 0 || ProdCurrOKQty < 0)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"产量不能为负数: 投入={ProdCurrAllQty}, 产出={ProdCurrOKQty}");
|
|||
|
|
//throw new ArgumentException($"产量不能为负数: 投入={ProdCurrAllQty}, 产出={ProdCurrOKQty}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Hourprod mh = new Hourprod
|
|||
|
|
{
|
|||
|
|
FDate = strDate,
|
|||
|
|
FHour = statisticalHour,
|
|||
|
|
ProdIn = ProdCurrAllQty,
|
|||
|
|
ProdOut = ProdCurrOKQty,
|
|||
|
|
TestTime = dateTime,
|
|||
|
|
Ppm = CommonMethods.Ppm,
|
|||
|
|
JiaDL = Convert.ToDecimal(CommonMethods.JiaDL)
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 尝试更新记录
|
|||
|
|
int res = CommonMethods.db.UpdateSingle(
|
|||
|
|
mh,
|
|||
|
|
it => new Hourprod
|
|||
|
|
{
|
|||
|
|
ProdIn = mh.ProdIn,
|
|||
|
|
ProdOut = mh.ProdOut,
|
|||
|
|
TestTime = mh.TestTime,
|
|||
|
|
Ppm = mh.Ppm,
|
|||
|
|
JiaDL = mh.JiaDL
|
|||
|
|
},
|
|||
|
|
it => it.FDate == mh.FDate && it.FHour == mh.FHour
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 如果更新失败(记录不存在),则新增记录
|
|||
|
|
if (res <= 0)
|
|||
|
|
{
|
|||
|
|
bool addResult = await CommonMethods.db.AddReturnBoolAsync<Hourprod>(mh);
|
|||
|
|
if (!addResult)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"保存小时产能新增记录失败");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 可以添加日志记录成功信息
|
|||
|
|
// Logger.Log($"成功更新/新增产能数据: 日期={strDate}, 小时={statisticalHour}, 时段={statisticalHour}:30~{(statisticalHour + 1) % 24}:29");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
// 这里应该添加错误日志记录
|
|||
|
|
LogHelper.Instance.WriteEX($"保存小时产能数据失败: ", ex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//string strErr = "";
|
|||
|
|
//DateTime dateTime = DateTime.Now;
|
|||
|
|
//string strDate = dateTime.ToString("yyyy-MM-dd");
|
|||
|
|
//int Min = dateTime.Minute;
|
|||
|
|
//int Hour = dateTime.Hour;
|
|||
|
|
//if (Min < 30)
|
|||
|
|
//{
|
|||
|
|
// Hour -= 1;
|
|||
|
|
//}
|
|||
|
|
//if (dateTime.Hour < 30 && dateTime.Hour == 0)
|
|||
|
|
//{
|
|||
|
|
// Hour = 0;
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
////读取PLC投入总数
|
|||
|
|
//int ProdCurrAllQty = GetToDayHourQty(Hour, true);
|
|||
|
|
////读取PLC产出数
|
|||
|
|
//int ProdCurrOKQty = GetToDayHourQty(Hour, false);
|
|||
|
|
//Hourprod mh = new Hourprod();
|
|||
|
|
|
|||
|
|
//mh.FDate = strDate;
|
|||
|
|
//mh.FHour = Hour;
|
|||
|
|
//mh.ProdIn = ProdCurrAllQty;
|
|||
|
|
//mh.ProdOut = ProdCurrOKQty;
|
|||
|
|
//mh.TestTime = DateTime.Now;
|
|||
|
|
//mh.Ppm = CommonMethods.Ppm;
|
|||
|
|
//mh.JiaDL = Convert.ToDecimal(CommonMethods.JiaDL);
|
|||
|
|
|
|||
|
|
////更新
|
|||
|
|
//int res = CommonMethods.db.UpdateSingle(mh, it => new Hourprod() { ProdIn = mh.ProdIn, ProdOut = mh.ProdOut, TestTime = DateTime.Now, Ppm = mh.Ppm, JiaDL = mh.JiaDL, },
|
|||
|
|
// it => it.FDate == mh.FDate && it.FHour == mh.FHour);
|
|||
|
|
//if (res <= 0) //更新失败就新增保存
|
|||
|
|
//{
|
|||
|
|
// CommonMethods.db.AddReturnBool<Hourprod>(mh);
|
|||
|
|
//}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 每小时产能读取处理
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="hour"></param>
|
|||
|
|
/// <param name="flag"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private int GetToDayHourQty(int hour, bool flag)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
string strAddr = "";
|
|||
|
|
|
|||
|
|
if (flag)//产出
|
|||
|
|
{
|
|||
|
|
strAddr = "D" + (1040 + hour);
|
|||
|
|
}
|
|||
|
|
else//良品数
|
|||
|
|
{
|
|||
|
|
strAddr = "D" + (1070 + hour);
|
|||
|
|
}
|
|||
|
|
int ProdNGQty = CommonMethods.plcDevices[0].ReadInt16(strAddr);
|
|||
|
|
return ProdNGQty;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
MessageBox.Show(ex.Message, "系统异常", MessageBoxButtons.OK, MessageBoxIcon.Hand);
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 5、设备状态
|
|||
|
|
/// <summary>
|
|||
|
|
/// 定时获取设备状态
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="mt"></param>
|
|||
|
|
///
|
|||
|
|
int OldStatues = Convert.ToInt32(IniConfigHelper.ReadIniData("上一次设备状态", "DeviceStatus", "1", CommonMethods.strDeviceStatusPath));//退出程序前设备状态
|
|||
|
|
//int StatuesCount = 0;
|
|||
|
|
DateTime StatuesBeginTime = DateTime.Now.AddMinutes(-6);
|
|||
|
|
string strGuidAlarm = IniConfigHelper.ReadIniData("上一次Guid", "DeviceGuid", Guid.NewGuid().ToString(), CommonMethods.strDeviceStatusPath);//退出程序前Guid
|
|||
|
|
bool run_AlarmMark = false;//特殊情况1标志(运行状态)
|
|||
|
|
bool run_IdleMark = false;//特殊情况2标志(闲置状态)
|
|||
|
|
bool isUpIdleAlarm = false;//闲置状态报警信息上传标志
|
|||
|
|
List<AlarmData> idleAlarmData = new List<AlarmData>();//闲置状态的报警信息
|
|||
|
|
|
|||
|
|
private async void ShowStateEven_Run()
|
|||
|
|
{
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.plcDevices.Count > 0 && CommonMethods.plcDevices != null)
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)//检查plc配置是否启用
|
|||
|
|
{
|
|||
|
|
DateTime Date = DateTime.Now;
|
|||
|
|
bool isUpload = false;
|
|||
|
|
string deviceStatus = string.Empty;
|
|||
|
|
string deviceStatusDesc = string.Empty;
|
|||
|
|
short NewStatus = CommonMethods.plcDevices[0].ReadInt16("D10");//读取新状态
|
|||
|
|
|
|||
|
|
if (NewStatus != 100)
|
|||
|
|
{
|
|||
|
|
//特殊情况1:运行->报警->……->运行
|
|||
|
|
if (NewStatus == 3 && OldStatues == 1) { run_AlarmMark = true; }//第一次进入报警状态
|
|||
|
|
if (NewStatus == 1) { run_AlarmMark = false; }//下一次运行状态,置位
|
|||
|
|
if (run_AlarmMark) { NewStatus = 3; }//报警状态后下一次运行状态期间一直是报警状态
|
|||
|
|
//特殊情况2:运行->闲置->……->运行
|
|||
|
|
if (NewStatus == 4 && OldStatues == 1) { run_IdleMark = true; }//第一次进入闲置状态
|
|||
|
|
if (NewStatus == 1) { run_IdleMark = false; }//下一次闲置状态,置位
|
|||
|
|
if (run_IdleMark) { NewStatus = 4; }//闲置状态后下一次运行状态期间一直是闲置状态
|
|||
|
|
|
|||
|
|
//闲置状态结束报警信息上传
|
|||
|
|
if (OldStatues == 4 && NewStatus != 4 && isUpIdleAlarm)
|
|||
|
|
{
|
|||
|
|
_ = UpIdleDataAsync(idleAlarmData, strGuidAlarm);//guid
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//设备状态信号灯变量
|
|||
|
|
CommonMethods.Statues = new List<bool> { NewStatus == 1, NewStatus == 2, NewStatus == 3, NewStatus == 4 };//bool类型的4个true状态
|
|||
|
|
|
|||
|
|
// 状态切换时生成新的 GUID
|
|||
|
|
if (NewStatus != OldStatues)
|
|||
|
|
{
|
|||
|
|
// 从 Alert 切换到非 Alert 状态时,上传报警信息
|
|||
|
|
if (OldStatues == 3 && NewStatus != 3)
|
|||
|
|
{
|
|||
|
|
ShowAlarmEven_Run(strGuidAlarm);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 只要状态变更,就生成新的 GUID
|
|||
|
|
strGuidAlarm = Guid.NewGuid().ToString(); // 强制生成新的 GUID
|
|||
|
|
|
|||
|
|
isUpload = true;
|
|||
|
|
//StatuesCount = 0;
|
|||
|
|
OldStatues = NewStatus;
|
|||
|
|
StatuesBeginTime = Convert.ToDateTime(Date);
|
|||
|
|
|
|||
|
|
//记录最新设备状态和Guid
|
|||
|
|
//CommonMethods.UpdateConfig("MES_CONFIG", "DeviceStatus", NewStatus.ToString());// 保存设备状态到xml文件
|
|||
|
|
//CommonMethods.UpdateConfig("MES_CONFIG", "Guid", strGuidAlarm);// 保存设备状态到xml文件
|
|||
|
|
|
|||
|
|
//CommonMethods.Configxml["MES_CONFIG"]["DeviceStatus"] = NewStatus.ToString(); // 保存设备状态到xml文件
|
|||
|
|
//CommonMethods.Configxml["MES_CONFIG"]["Guid"] = strGuidAlarm; // 保存设备状态到xml文件
|
|||
|
|
//CommonMethods.WriteXmlFile(CommonMethods.Configxml, CommonMethods.xmlFilePath);
|
|||
|
|
|
|||
|
|
IniConfigHelper.WriteIniData("上一次设备状态", "DeviceStatus", NewStatus.ToString(), CommonMethods.strDeviceStatusPath);
|
|||
|
|
IniConfigHelper.WriteIniData("上一次Guid", "DeviceGuid", strGuidAlarm, CommonMethods.strDeviceStatusPath);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// 同种状态持续 5 分钟时上传状态信息
|
|||
|
|
//StatuesCount++;
|
|||
|
|
//if (StatuesCount >= 5 * 60)
|
|||
|
|
//{
|
|||
|
|
// isUpload = true;
|
|||
|
|
// StatuesCount = 0;
|
|||
|
|
//}
|
|||
|
|
if (Date.Subtract(StatuesBeginTime).TotalSeconds < 5 * 60 && Date.Subtract(StatuesBeginTime).TotalSeconds > 4 * 60)
|
|||
|
|
{
|
|||
|
|
isUpload = true;
|
|||
|
|
StatuesBeginTime = DateTime.Now;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 根据状态设置设备状态和描述
|
|||
|
|
switch (NewStatus)
|
|||
|
|
{
|
|||
|
|
case 1:
|
|||
|
|
deviceStatus = "Run";
|
|||
|
|
deviceStatusDesc = "正常运行";
|
|||
|
|
break;
|
|||
|
|
case 2://取消
|
|||
|
|
deviceStatus = "Maintain";
|
|||
|
|
deviceStatusDesc = "停止运行";
|
|||
|
|
break;
|
|||
|
|
case 3:
|
|||
|
|
deviceStatus = "Alert";
|
|||
|
|
deviceStatusDesc = "故障调试";
|
|||
|
|
// Alert 状态时上传报警信息
|
|||
|
|
ShowAlarmEven_Run(strGuidAlarm);
|
|||
|
|
break;
|
|||
|
|
case 4:
|
|||
|
|
deviceStatus = "Idle";
|
|||
|
|
deviceStatusDesc = "闲置待机";
|
|||
|
|
ShowStuesEven_Run(strGuidAlarm);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 上传设备状态信息
|
|||
|
|
if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected && isUpload && (NewStatus == 1 || NewStatus == 3 || NewStatus == 4))
|
|||
|
|
{
|
|||
|
|
var (success, message) = await CommonMethods.hbgMes.UploadEquStatusAsync(
|
|||
|
|
CommonMethods.mesConfig.DeviceStatus,
|
|||
|
|
CommonMethods.mesConfig.siteCode,
|
|||
|
|
CommonMethods.mesConfig.lineCode,
|
|||
|
|
CommonMethods.mesConfig.equipNum,
|
|||
|
|
CommonMethods.mesConfig.MaterialCode,
|
|||
|
|
CommonMethods.mesConfig.mesUserName,
|
|||
|
|
strGuidAlarm, // RUN 状态时传空
|
|||
|
|
deviceStatus,
|
|||
|
|
null
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
//if (success)
|
|||
|
|
//{
|
|||
|
|
// StatuesCount = 0;
|
|||
|
|
//}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteEX(ex);
|
|||
|
|
}
|
|||
|
|
Thread.Sleep(100);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#region 触摸屏弹窗
|
|||
|
|
private async void ShowStuesEven_Run(string strGuid)
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.plcDevices[0].IsConnected)
|
|||
|
|
{
|
|||
|
|
string strCode = "";
|
|||
|
|
string alarmName = "";
|
|||
|
|
short HMIStatus = CommonMethods.plcDevices[0].ReadInt16("D40");
|
|||
|
|
if (HMIStatus != 0)
|
|||
|
|
{
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, "触发了手动HMI弹窗功能".Translated());
|
|||
|
|
switch (HMIStatus) //注意:B1-D12都为闲置代码,上传代码是只需上传闲置代码
|
|||
|
|
{
|
|||
|
|
//case 1://取消
|
|||
|
|
// strCode = "B1";
|
|||
|
|
// alarmName = "计划维保";
|
|||
|
|
// CommonMethods.AddDataMonitorLog(0, "B1 计划维保");
|
|||
|
|
|
|||
|
|
// break;
|
|||
|
|
//case 2://取消
|
|||
|
|
// strCode = "B2";
|
|||
|
|
// alarmName = "无生产计划";
|
|||
|
|
// CommonMethods.AddDataMonitorLog(0, "B2 无生产计划");
|
|||
|
|
// break;
|
|||
|
|
//case 3://取消
|
|||
|
|
// strCode = "B3";
|
|||
|
|
// alarmName = "样品、试产";
|
|||
|
|
// CommonMethods.AddDataMonitorLog(0, "B3 样品、试产");
|
|||
|
|
// break;
|
|||
|
|
//case 4://取消
|
|||
|
|
// strCode = "B4";
|
|||
|
|
// alarmName = "其他计划停机";
|
|||
|
|
// CommonMethods.AddDataMonitorLog(0, "B4.其他计划停机");
|
|||
|
|
// break;
|
|||
|
|
case 5:
|
|||
|
|
strCode = "D1";
|
|||
|
|
alarmName = "设备故障".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 6:
|
|||
|
|
strCode = "D2";
|
|||
|
|
alarmName = "设备转型".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 7:
|
|||
|
|
strCode = "D3";
|
|||
|
|
alarmName = "工程变更".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 8:
|
|||
|
|
strCode = "D4";
|
|||
|
|
alarmName = "MES停机".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 9:
|
|||
|
|
strCode = "D5";
|
|||
|
|
alarmName = "品质异常".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 10:
|
|||
|
|
strCode = "D6";
|
|||
|
|
alarmName = "配件,物料更换".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 11:
|
|||
|
|
strCode = "D7";
|
|||
|
|
alarmName = "来料不良".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 12:
|
|||
|
|
strCode = "D8";
|
|||
|
|
alarmName = "待料".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 13:
|
|||
|
|
strCode = "D9";
|
|||
|
|
alarmName = "品质检查".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 14:
|
|||
|
|
strCode = "D10";
|
|||
|
|
alarmName = "清洁点检".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 15:
|
|||
|
|
strCode = "D11";
|
|||
|
|
alarmName = "环境不满足".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
case 16:
|
|||
|
|
strCode = "D12";
|
|||
|
|
alarmName = "其它非计划停机".Translated();
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, $"{strCode} {alarmName}");
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
|
|||
|
|
{
|
|||
|
|
List<AlarmData> alarmObj = new List<AlarmData>();
|
|||
|
|
AlarmData alarmData = new AlarmData();
|
|||
|
|
alarmData.AlarmCode = strCode;
|
|||
|
|
alarmData.StartTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|||
|
|
alarmData.EndTime = "";
|
|||
|
|
alarmData.AlarmType = "非计划损失";
|
|||
|
|
alarmData.AlarmContent = alarmName;
|
|||
|
|
alarmObj.Add(alarmData);
|
|||
|
|
|
|||
|
|
//闲置报警上传标志
|
|||
|
|
isUpIdleAlarm = true;
|
|||
|
|
idleAlarmData.Add(alarmData);
|
|||
|
|
|
|||
|
|
//上传报警
|
|||
|
|
var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode,
|
|||
|
|
CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, alarmObj, strGuid);
|
|||
|
|
if (success)
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, "HMI手动弹窗状态已上传成功,代码".Translated() + $":{strCode}");
|
|||
|
|
}
|
|||
|
|
CommonMethods.plcDevices[0].WriteInt16("D40", 0);
|
|||
|
|
//if (IsSuccess)
|
|||
|
|
// CommonMethods.AddDataMonitorLog(0, $"D40已复位0".Translated());
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// HMI手动弹窗结束状态上传
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="idleAlarmDate"></param>
|
|||
|
|
/// <param name="strGuidAlarm"></param>
|
|||
|
|
/// <returns></returns>
|
|||
|
|
private async Task UpIdleDataAsync(List<AlarmData> idleAlarmDate, string strGuidAlarm)
|
|||
|
|
{
|
|||
|
|
if (idleAlarmDate.Count == 0) { return; }
|
|||
|
|
string strCode = "";
|
|||
|
|
foreach (var item in idleAlarmDate)
|
|||
|
|
{
|
|||
|
|
item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|||
|
|
strCode = item.AlarmCode + ",";
|
|||
|
|
}
|
|||
|
|
if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
|
|||
|
|
{
|
|||
|
|
//上传报警
|
|||
|
|
var (success, message) = await CommonMethods.hbgMes.UploadEquAlarmAsync(CommonMethods.mesConfig.DeviceAlarm, CommonMethods.mesConfig.siteCode, CommonMethods.mesConfig.lineCode,
|
|||
|
|
CommonMethods.mesConfig.equipNum, CommonMethods.mesConfig.MaterialCode, CommonMethods.mesConfig.mesUserName, idleAlarmDate, strGuidAlarm);
|
|||
|
|
if (success)
|
|||
|
|
CommonMethods.AddDataMonitorLog(0, "HMI手动弹窗结束状态已上传成功,代码".Translated() + $":{strCode.TrimEnd(',')}");
|
|||
|
|
}
|
|||
|
|
idleAlarmData.Clear();
|
|||
|
|
isUpIdleAlarm = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 6、设备报警
|
|||
|
|
//报警表单数据
|
|||
|
|
List<AlarmForm> listAlarmForm = null;
|
|||
|
|
public void GetAlarmData()
|
|||
|
|
{
|
|||
|
|
//加载PLC报警文件
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
string strFileName = System.Environment.CurrentDirectory + "\\欧姆龙报警寄存器对应表.csv";
|
|||
|
|
listAlarmForm = CSVHelper<AlarmForm>.ReadCSV<AlarmForm>(strFileName);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
MessageBox.Show("加载报警文件失败!");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 报警信息读取
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="mt"></param>
|
|||
|
|
/// <param name="resByte"></param>
|
|||
|
|
List<AlarmData> listOld = new List<AlarmData>();
|
|||
|
|
List<AlarmData> listNew = new List<AlarmData>();
|
|||
|
|
List<AlarmStatus> listAlarmStatus = null;
|
|||
|
|
private void ShowAlarmEven_Run(string strGuidAlarm)
|
|||
|
|
{
|
|||
|
|
if (!CommonMethods.IsRun || !CommonMethods.plcDevices[0].IsConnected)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 1. 读取 PLC 报警信息
|
|||
|
|
var alarmStatusList = ReadAlarmStatusFromPLC();
|
|||
|
|
if (alarmStatusList == null || listAlarmForm == null)//true
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 解析报警信息并生成新的报警列表
|
|||
|
|
var newAlarms = ParseAlarmStatus(alarmStatusList, strGuidAlarm);
|
|||
|
|
if (newAlarms.Count > 0)
|
|||
|
|
{
|
|||
|
|
// 3. 检测新报警并添加到旧报警列表,上传第一次报警信息
|
|||
|
|
DetectNewAlarmsAsync(newAlarms);
|
|||
|
|
|
|||
|
|
// 4. 显示新报警信息
|
|||
|
|
DisplayAlarmInfo(newAlarms);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 5. 检测已取消的报警并处理
|
|||
|
|
var canceledAlarms = DetectCanceledAlarms(newAlarms);
|
|||
|
|
if (canceledAlarms.Count > 0)
|
|||
|
|
{
|
|||
|
|
// 6. 记录已取消的报警信息(保存本地)
|
|||
|
|
LogCanceledAlarms(canceledAlarms);
|
|||
|
|
|
|||
|
|
// 7. 上传已取消的报警信息(报警结束上传一次)
|
|||
|
|
UploadCanceledAlarmsAsync(canceledAlarms, strGuidAlarm);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteEX(ex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 从 PLC 读取报警状态
|
|||
|
|
/// </summary>
|
|||
|
|
private List<AlarmStatus> ReadAlarmStatusFromPLC()
|
|||
|
|
{
|
|||
|
|
//string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|||
|
|
//JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>("D10150", DataType.ArrByte, 5000);
|
|||
|
|
|
|||
|
|
//if (resByte.IsSuccess && resByte != null)
|
|||
|
|
//{
|
|||
|
|
// int startPlcAddr = 10150; // 读取起始地址
|
|||
|
|
// return PLCAlarmParseHelper.OmronFinsByte2Status(startPlcAddr, resByte.Content);
|
|||
|
|
//}
|
|||
|
|
string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|||
|
|
// 读取足够的字节覆盖所有可能的报警地址
|
|||
|
|
int startAddr = 10150;
|
|||
|
|
int endAddr = 14750; // 根据实际最大地址调整
|
|||
|
|
int wordCount = endAddr - startAddr + 1;
|
|||
|
|
int byteCount = wordCount * 2; // 每个字2字节
|
|||
|
|
|
|||
|
|
JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>(
|
|||
|
|
$"D{startAddr}", DataType.ArrByte, (ushort)byteCount);
|
|||
|
|
|
|||
|
|
if (resByte.IsSuccess && resByte.Content != null)
|
|||
|
|
{
|
|||
|
|
return PLCAlarmParseHelper.OmronFinsByte2Status(startAddr, resByte.Content);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 解析报警状态并生成新的报警列表
|
|||
|
|
/// </summary>
|
|||
|
|
private List<AlarmData> ParseAlarmStatus(List<AlarmStatus> alarmStatusList, string strGuidAlarm)
|
|||
|
|
{
|
|||
|
|
string Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|||
|
|
|
|||
|
|
var alarmTypeMap = new Dictionary<char, string> // 定义报警类型映射字典
|
|||
|
|
{
|
|||
|
|
{'1', "停机报警"},
|
|||
|
|
{'2', "非停机报警"},
|
|||
|
|
};
|
|||
|
|
switch (LanguageManager.LanguageCode)
|
|||
|
|
{
|
|||
|
|
case "en"://英语报警信息
|
|||
|
|
return alarmStatusList
|
|||
|
|
.Where(status => status.Status)
|
|||
|
|
.Join(
|
|||
|
|
listAlarmForm,
|
|||
|
|
status => status.PLCAdress,
|
|||
|
|
form => form.PLCAdress,
|
|||
|
|
(status, form) =>
|
|||
|
|
{
|
|||
|
|
var alarmContent = string.IsNullOrEmpty(form.EnAlarmContent)
|
|||
|
|
? status.PLCAdress
|
|||
|
|
: form.EnAlarmContent;
|
|||
|
|
string alarmType = "停机报警"; // 默认值
|
|||
|
|
if (form.AlarmCode?.Length >= 3)
|
|||
|
|
{
|
|||
|
|
char thirdChar = form.AlarmCode[2];
|
|||
|
|
// 尝试从字典获取对应的值
|
|||
|
|
if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType))
|
|||
|
|
{
|
|||
|
|
alarmType = mappedType;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return new AlarmData
|
|||
|
|
{
|
|||
|
|
AlarmGuid = strGuidAlarm,
|
|||
|
|
PLCAdress = status.PLCAdress,
|
|||
|
|
AlarmCode = form.AlarmCode,
|
|||
|
|
AlarmContent = alarmContent,
|
|||
|
|
AlarmType = alarmType,
|
|||
|
|
AlarmDesc = alarmContent,
|
|||
|
|
AlarmState = "1",
|
|||
|
|
StartTime = Date,
|
|||
|
|
EndTime = "",
|
|||
|
|
Flag = 0
|
|||
|
|
};
|
|||
|
|
})
|
|||
|
|
.ToList();
|
|||
|
|
case "hu"://匈牙利语报警信息
|
|||
|
|
return alarmStatusList
|
|||
|
|
.Where(status => status.Status)
|
|||
|
|
.Join(
|
|||
|
|
listAlarmForm,
|
|||
|
|
status => status.PLCAdress,
|
|||
|
|
form => form.PLCAdress,
|
|||
|
|
(status, form) =>
|
|||
|
|
{
|
|||
|
|
var alarmContent = string.IsNullOrEmpty(form.HuAlarmContent)
|
|||
|
|
? status.PLCAdress
|
|||
|
|
: form.HuAlarmContent;
|
|||
|
|
string alarmType = "停机报警"; // 默认值
|
|||
|
|
if (form.AlarmCode?.Length >= 3)
|
|||
|
|
{
|
|||
|
|
char thirdChar = form.AlarmCode[2];
|
|||
|
|
// 尝试从字典获取对应的值
|
|||
|
|
if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType))
|
|||
|
|
{
|
|||
|
|
alarmType = mappedType;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return new AlarmData
|
|||
|
|
{
|
|||
|
|
AlarmGuid = strGuidAlarm,
|
|||
|
|
PLCAdress = status.PLCAdress,
|
|||
|
|
AlarmCode = form.AlarmCode,
|
|||
|
|
AlarmContent = alarmContent,
|
|||
|
|
AlarmType = alarmType,
|
|||
|
|
AlarmDesc = alarmContent,
|
|||
|
|
AlarmState = "1",
|
|||
|
|
StartTime = Date,
|
|||
|
|
EndTime = "",
|
|||
|
|
Flag = 0
|
|||
|
|
};
|
|||
|
|
})
|
|||
|
|
.ToList();
|
|||
|
|
case "ms"://马来语报警信息
|
|||
|
|
return alarmStatusList
|
|||
|
|
.Where(status => status.Status)
|
|||
|
|
.Join(
|
|||
|
|
listAlarmForm,
|
|||
|
|
status => status.PLCAdress,
|
|||
|
|
form => form.PLCAdress,
|
|||
|
|
(status, form) =>
|
|||
|
|
{
|
|||
|
|
var alarmContent = string.IsNullOrEmpty(form.MsAlarmContent)
|
|||
|
|
? status.PLCAdress
|
|||
|
|
: form.MsAlarmContent;
|
|||
|
|
string alarmType = "停机报警"; // 默认值
|
|||
|
|
if (form.AlarmCode?.Length >= 3)
|
|||
|
|
{
|
|||
|
|
char thirdChar = form.AlarmCode[2];
|
|||
|
|
// 尝试从字典获取对应的值
|
|||
|
|
if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType))
|
|||
|
|
{
|
|||
|
|
alarmType = mappedType;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return new AlarmData
|
|||
|
|
{
|
|||
|
|
AlarmGuid = strGuidAlarm,
|
|||
|
|
PLCAdress = status.PLCAdress,
|
|||
|
|
AlarmCode = form.AlarmCode,
|
|||
|
|
AlarmContent = alarmContent,
|
|||
|
|
AlarmType = alarmType,
|
|||
|
|
AlarmDesc = alarmContent,
|
|||
|
|
AlarmState = "1",
|
|||
|
|
StartTime = Date,
|
|||
|
|
EndTime = "",
|
|||
|
|
Flag = 0
|
|||
|
|
};
|
|||
|
|
})
|
|||
|
|
.ToList();
|
|||
|
|
case "zh":
|
|||
|
|
default:
|
|||
|
|
return alarmStatusList
|
|||
|
|
.Where(status => status.Status)
|
|||
|
|
.Join(
|
|||
|
|
listAlarmForm,
|
|||
|
|
status => status.PLCAdress,
|
|||
|
|
form => form.PLCAdress,
|
|||
|
|
(status, form) =>
|
|||
|
|
{
|
|||
|
|
var alarmContent = string.IsNullOrEmpty(form.AlarmContent)
|
|||
|
|
? status.PLCAdress
|
|||
|
|
: form.AlarmContent;
|
|||
|
|
string alarmType = "停机报警"; // 默认值
|
|||
|
|
if (form.AlarmCode?.Length >= 3)
|
|||
|
|
{
|
|||
|
|
char thirdChar = form.AlarmCode[2];
|
|||
|
|
// 尝试从字典获取对应的值
|
|||
|
|
if (alarmTypeMap.TryGetValue(thirdChar, out string mappedType))
|
|||
|
|
{
|
|||
|
|
alarmType = mappedType;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return new AlarmData
|
|||
|
|
{
|
|||
|
|
AlarmGuid = strGuidAlarm,
|
|||
|
|
PLCAdress = status.PLCAdress,
|
|||
|
|
AlarmCode = form.AlarmCode,
|
|||
|
|
AlarmContent = alarmContent,
|
|||
|
|
AlarmType = alarmType,
|
|||
|
|
AlarmDesc = alarmContent,
|
|||
|
|
AlarmState = "1",
|
|||
|
|
StartTime = Date,
|
|||
|
|
EndTime = "",
|
|||
|
|
Flag = 0
|
|||
|
|
};
|
|||
|
|
})
|
|||
|
|
.ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*switch (LanguageManager.LanguageCode)
|
|||
|
|
{
|
|||
|
|
case "en"://英语报警信息
|
|||
|
|
return alarmStatusList
|
|||
|
|
.Where(s => s.Status)
|
|||
|
|
.Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
|
|||
|
|
{
|
|||
|
|
AlarmGuid = strGuidAlarm,
|
|||
|
|
PLCAdress = s.PLCAdress,
|
|||
|
|
AlarmCode = f.AlarmCode,
|
|||
|
|
AlarmContent = f.EnAlarmContent == "" ? s.PLCAdress : f.EnAlarmContent,
|
|||
|
|
AlarmType = "停机报警",
|
|||
|
|
AlarmDesc = f.EnAlarmContent == "" ? s.PLCAdress : f.EnAlarmContent,
|
|||
|
|
AlarmState = "1",
|
|||
|
|
StartTime = Date,
|
|||
|
|
EndTime = "",//Date
|
|||
|
|
Flag = 0
|
|||
|
|
}).ToList();
|
|||
|
|
case "hu"://匈牙利语报警信息
|
|||
|
|
return alarmStatusList
|
|||
|
|
.Where(s => s.Status)
|
|||
|
|
.Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
|
|||
|
|
{
|
|||
|
|
AlarmGuid = strGuidAlarm,
|
|||
|
|
PLCAdress = s.PLCAdress,
|
|||
|
|
AlarmCode = f.AlarmCode,
|
|||
|
|
AlarmContent = f.HuAlarmContent == "" ? s.PLCAdress : f.HuAlarmContent,
|
|||
|
|
AlarmType = "停机报警",
|
|||
|
|
AlarmDesc = f.HuAlarmContent == "" ? s.PLCAdress : f.HuAlarmContent,
|
|||
|
|
AlarmState = "1",
|
|||
|
|
StartTime = Date,
|
|||
|
|
EndTime = "",//Date
|
|||
|
|
Flag = 0
|
|||
|
|
}).ToList();
|
|||
|
|
case "ms"://马来语报警信息
|
|||
|
|
return alarmStatusList
|
|||
|
|
.Where(s => s.Status)
|
|||
|
|
.Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
|
|||
|
|
{
|
|||
|
|
AlarmGuid = strGuidAlarm,
|
|||
|
|
PLCAdress = s.PLCAdress,
|
|||
|
|
AlarmCode = f.AlarmCode,
|
|||
|
|
AlarmContent = f.MsAlarmContent == "" ? s.PLCAdress : f.MsAlarmContent,
|
|||
|
|
AlarmType = "停机报警",
|
|||
|
|
AlarmDesc = f.MsAlarmContent == "" ? s.PLCAdress : f.MsAlarmContent,
|
|||
|
|
AlarmState = "1",
|
|||
|
|
StartTime = Date,
|
|||
|
|
EndTime = "",//Date
|
|||
|
|
Flag = 0
|
|||
|
|
}).ToList();
|
|||
|
|
case "zh"://中语报警信息
|
|||
|
|
default:
|
|||
|
|
return alarmStatusList
|
|||
|
|
.Where(s => s.Status)
|
|||
|
|
.Join(listAlarmForm, s => s.PLCAdress, f => f.PLCAdress, (s, f) => new AlarmData()
|
|||
|
|
{
|
|||
|
|
AlarmGuid = strGuidAlarm,
|
|||
|
|
PLCAdress = s.PLCAdress,
|
|||
|
|
AlarmCode = f.AlarmCode,
|
|||
|
|
AlarmContent = f.AlarmContent == "" ? s.PLCAdress : f.AlarmContent,
|
|||
|
|
AlarmType = "停机报警",
|
|||
|
|
AlarmDesc = f.AlarmContent == "" ? s.PLCAdress : f.AlarmContent,
|
|||
|
|
AlarmState = "1",
|
|||
|
|
StartTime = Date,
|
|||
|
|
EndTime = "",//Date
|
|||
|
|
Flag = 0
|
|||
|
|
}).ToList();
|
|||
|
|
}*/
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 检测新报警并添加到旧报警列表
|
|||
|
|
/// </summary>
|
|||
|
|
private void DetectNewAlarmsAsync(List<AlarmData> newAlarms)
|
|||
|
|
{
|
|||
|
|
foreach (var alarm in newAlarms)
|
|||
|
|
{
|
|||
|
|
if (!listOld.Any(o => o.PLCAdress == alarm.PLCAdress))
|
|||
|
|
{
|
|||
|
|
listOld.Add(alarm);
|
|||
|
|
|
|||
|
|
// 4.5 新增逻辑(报警开始上传一次)
|
|||
|
|
UploadCanceledAlarmsAsync(newAlarms, strGuidAlarm);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 显示报警信息
|
|||
|
|
/// </summary>
|
|||
|
|
private void DisplayAlarmInfo(List<AlarmData> newAlarms)
|
|||
|
|
{
|
|||
|
|
StringBuilder sb = new StringBuilder();
|
|||
|
|
newAlarms.ForEach(r => sb.Append($"{r.AlarmContent} "));
|
|||
|
|
|
|||
|
|
if (sb.Length > 0)
|
|||
|
|
{
|
|||
|
|
CommonMethods.SlideAlarmText = sb.ToString().Substring(0, sb.Length - 10);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 检测已取消的报警
|
|||
|
|
/// </summary>
|
|||
|
|
private List<AlarmData> DetectCanceledAlarms(List<AlarmData> newAlarms)
|
|||
|
|
{
|
|||
|
|
var canceledAlarms = new List<AlarmData>();
|
|||
|
|
var listOldAlarm = new List<AlarmData>(listOld);
|
|||
|
|
|
|||
|
|
foreach (var item in listOldAlarm)
|
|||
|
|
{
|
|||
|
|
if (!newAlarms.Any(n => n.PLCAdress == item.PLCAdress))
|
|||
|
|
{
|
|||
|
|
item.EndTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|||
|
|
canceledAlarms.Add(item);
|
|||
|
|
listOld.Remove(item);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return canceledAlarms;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 记录已取消的报警信息
|
|||
|
|
/// </summary>
|
|||
|
|
private void LogCanceledAlarms(List<AlarmData> canceledAlarms)
|
|||
|
|
{
|
|||
|
|
var nowDate = DateTime.Now;
|
|||
|
|
string basePath = $@"{CommonMethods.strAlarmLogspath}\{nowDate.Year}\{nowDate.Month}";
|
|||
|
|
string fileName = $@"{nowDate.Day}.csv";
|
|||
|
|
string title = "GUID,报警地址,故障代码,报警内容,开始时间,结束时间,是否停机";
|
|||
|
|
string alarmContent = string.Join("\n", canceledAlarms.Select(m1 =>
|
|||
|
|
$"{m1.AlarmGuid},{m1.PLCAdress},{m1.AlarmCode},{m1.AlarmContent},{m1.StartTime},{m1.EndTime},{m1.AlarmType}"));
|
|||
|
|
|
|||
|
|
CSVHelper<AlarmCSVData>.WriterCSV(basePath, fileName, title, alarmContent);
|
|||
|
|
|
|||
|
|
foreach (var m1 in canceledAlarms)
|
|||
|
|
{
|
|||
|
|
var alarm = new SysLog
|
|||
|
|
{
|
|||
|
|
InsertTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
|||
|
|
LogType = "报警日志",
|
|||
|
|
Note = m1.AlarmContent == "" ? m1.PLCAdress : m1.AlarmContent,
|
|||
|
|
AlarmType = "错误",
|
|||
|
|
Operater = CommonMethods.currentAdmin.LoginName,
|
|||
|
|
VarName = m1.PLCAdress,
|
|||
|
|
AlarmSet = "",
|
|||
|
|
AlarmValue = "1",
|
|||
|
|
};
|
|||
|
|
CommonMethods.AddAlarmLog(alarm);
|
|||
|
|
Task.Run(() => { SaveAlarmCount(canceledAlarms); Thread.Sleep(50); });
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 上传已取消的报警信息
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
private Dictionary<string, string> _lastAlarmContents = new Dictionary<string, string>();
|
|||
|
|
/// <summary>
|
|||
|
|
/// 上传报警
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="canceledAlarms"></param>
|
|||
|
|
/// <param name="strGuidAlarm"></param>
|
|||
|
|
private void UploadCanceledAlarmsAsync(List<AlarmData> canceledAlarms, string strGuidAlarm)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < canceledAlarms.Count; i++)
|
|||
|
|
{
|
|||
|
|
var currentAlarm = canceledAlarms[i];
|
|||
|
|
string currentContent = currentAlarm.AlarmContent;
|
|||
|
|
// 检查EndTime是否有有效值(非null且非空字符串)
|
|||
|
|
bool hasEndTime = !string.IsNullOrEmpty(currentAlarm.EndTime);
|
|||
|
|
|
|||
|
|
// 检查当前AlarmContent是否存在历史记录
|
|||
|
|
bool contentChanged = true;
|
|||
|
|
if (_lastAlarmContents.TryGetValue(currentContent, out string lastContent))
|
|||
|
|
{
|
|||
|
|
// 内容相同,标记为未改变
|
|||
|
|
if (currentContent == lastContent)
|
|||
|
|
{
|
|||
|
|
contentChanged = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 决定是否上传:内容改变 或者 内容未变但EndTime有值
|
|||
|
|
bool shouldUpload = contentChanged || hasEndTime;
|
|||
|
|
|
|||
|
|
if (shouldUpload)
|
|||
|
|
{
|
|||
|
|
var alarmList = new List<AlarmData> { canceledAlarms[i] };
|
|||
|
|
if (CommonMethods.sysConfig.MesModeSwitching && CommonMethods.mesConfig.isConnected)
|
|||
|
|
{
|
|||
|
|
CommonMethods.hbgMes.UploadEquAlarmAsync(
|
|||
|
|
CommonMethods.mesConfig.DeviceAlarm,
|
|||
|
|
CommonMethods.mesConfig.siteCode,
|
|||
|
|
CommonMethods.mesConfig.lineCode,
|
|||
|
|
CommonMethods.mesConfig.equipNum,
|
|||
|
|
CommonMethods.mesConfig.MaterialCode,
|
|||
|
|
CommonMethods.mesConfig.mesUserName,
|
|||
|
|
alarmList,
|
|||
|
|
strGuidAlarm
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新历史记录
|
|||
|
|
if (_lastAlarmContents.ContainsKey(currentContent))
|
|||
|
|
{
|
|||
|
|
_lastAlarmContents[currentContent] = currentContent;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
_lastAlarmContents.Add(currentContent, currentContent);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 报警保存
|
|||
|
|
/// </summary>
|
|||
|
|
private async Task SaveAlarmCount(List<AlarmData> alarmDatas)
|
|||
|
|
{
|
|||
|
|
bool ISAdd = false;
|
|||
|
|
var recordToUpdate = new AlarmCountEntry();
|
|||
|
|
|
|||
|
|
DateTime today = DateTime.Today;
|
|||
|
|
DateTime upTime = DateTime.Now;
|
|||
|
|
var listAlarmStatistics = CommonMethods.db.QueryWhereList<AlarmCountEntry>(it => Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
|
|||
|
|
List<AlarmCountEntry> fd = new List<AlarmCountEntry>();
|
|||
|
|
if (listAlarmStatistics != null)
|
|||
|
|
{
|
|||
|
|
alarmDatas.ForEach(async r =>
|
|||
|
|
{
|
|||
|
|
recordToUpdate = listAlarmStatistics.FirstOrDefault(x => x.PLCAdress.Trim() == r.PLCAdress);
|
|||
|
|
if (recordToUpdate != null)
|
|||
|
|
{
|
|||
|
|
await CommonMethods.db.UpdateAsync<AlarmCountEntry>(it => it.AlarmCount == it.AlarmCount + 1, it => it.PLCAdress == r.PLCAdress && Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
ISAdd = true;
|
|||
|
|
AlarmCountEntry alarm = new AlarmCountEntry();
|
|||
|
|
alarm.PLCAdress = r.PLCAdress;
|
|||
|
|
alarm.AlarmContent = r.AlarmContent;
|
|||
|
|
alarm.AlarmCount = 1;
|
|||
|
|
alarm.Class = CommonMethods.strClass;
|
|||
|
|
alarm.AlarmTime = upTime;
|
|||
|
|
fd.Add(alarm);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
});
|
|||
|
|
if (ISAdd)
|
|||
|
|
{
|
|||
|
|
bool res = await CommonMethods.db.AddReturnBoolAsync(fd);
|
|||
|
|
ISAdd = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
foreach (var m in listNew)
|
|||
|
|
{
|
|||
|
|
AlarmCountEntry alarm = new AlarmCountEntry();
|
|||
|
|
alarm.PLCAdress = m.PLCAdress;
|
|||
|
|
alarm.AlarmContent = m.AlarmContent;
|
|||
|
|
alarm.AlarmCount = 1;
|
|||
|
|
alarm.Class = CommonMethods.strClass;
|
|||
|
|
alarm.AlarmTime = today;
|
|||
|
|
fd.Add(alarm);
|
|||
|
|
}
|
|||
|
|
CommonMethods.db.AddReturnBool(fd);
|
|||
|
|
}
|
|||
|
|
await GetASqlAlarmData(DateTime.Today, CommonMethods.strClass);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 读取数据库报警信息
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="today"></param>
|
|||
|
|
/// <param name="strClass"></param>
|
|||
|
|
public async Task GetASqlAlarmData(DateTime today, string strClass)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
List<ChartDataType> chartAlarms = new List<ChartDataType>();
|
|||
|
|
List<AlarmCountEntry> AlarmDatas = null;
|
|||
|
|
List<string> List_X = new List<string>();
|
|||
|
|
List<int> List_Y = new List<int>();
|
|||
|
|
|
|||
|
|
DateTime baiClassStart = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 8:30:00"));
|
|||
|
|
DateTime baiClassEnd = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 20:29:59"));
|
|||
|
|
|
|||
|
|
DateTime yeClassStart = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 20:30:00"));
|
|||
|
|
DateTime yeClassEnd = Convert.ToDateTime(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd 8:29:59"));
|
|||
|
|
|
|||
|
|
|
|||
|
|
if (strClass == "全天".Translated())
|
|||
|
|
{
|
|||
|
|
AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => Convert.ToDateTime(it.AlarmTime.ToString("yyyy-MM-dd")) == today);
|
|||
|
|
}
|
|||
|
|
else if (strClass == "白班".Translated())
|
|||
|
|
{
|
|||
|
|
AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => it.AlarmTime >= baiClassStart && it.AlarmTime <= baiClassEnd && it.Class == strClass);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
AlarmDatas = CommonMethods.db.QueryList<AlarmCountEntry>("AlarmCount", 10, it => it.AlarmTime >= yeClassStart && it.AlarmTime <= yeClassEnd && it.Class == strClass);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (AlarmDatas != null && AlarmDatas.Count > 0)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
for (int i = 0; i < AlarmDatas.Count; i++)
|
|||
|
|
{
|
|||
|
|
chartAlarms.Add(new ChartDataType()
|
|||
|
|
{
|
|||
|
|
DataType = AlarmDatas[i].AlarmContent,
|
|||
|
|
DataCount = (int)AlarmDatas[i].AlarmCount
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
CommonMethods.Lst_AlarmTop10_Qty = chartAlarms;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
CommonMethods.Lst_AlarmTop10_Qty = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 下发权限给PLC
|
|||
|
|
/// <summary>
|
|||
|
|
/// 下发权限到PLC
|
|||
|
|
/// </summary>
|
|||
|
|
///
|
|||
|
|
private async Task SendRightToPLCAsync()
|
|||
|
|
{
|
|||
|
|
ushort quanxian = 1;
|
|||
|
|
switch (CommonMethods.currentAdmin.LoginLevel)
|
|||
|
|
{
|
|||
|
|
case "操作员":
|
|||
|
|
quanxian = 1;
|
|||
|
|
break;
|
|||
|
|
case "工程师":
|
|||
|
|
quanxian = 2;
|
|||
|
|
break;
|
|||
|
|
case "管理员":
|
|||
|
|
quanxian = 3;
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
foreach (var plc in CommonMethods.plcDevices)
|
|||
|
|
{
|
|||
|
|
if (plcDeviceMapping.TryGetValue(plc, out var plcDevices))
|
|||
|
|
{
|
|||
|
|
foreach (var plcDevice in plcDevices)
|
|||
|
|
{
|
|||
|
|
if (plcDevice.IsConnected)
|
|||
|
|
{
|
|||
|
|
JYResult result = await Task.Run(() => plc.WriteValue("D21", (short)quanxian, DataType.Short));
|
|||
|
|
if (result.IsSuccess)
|
|||
|
|
{
|
|||
|
|
CommonMethods.AddDataMonitorLog(1, $"Write_PLC_permission_Successful");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
CommonMethods.AddDataMonitorLog(2, $"Write_PLC_permission(D15)_Failed");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 获取白夜班次
|
|||
|
|
bool qiehuan = false;
|
|||
|
|
private void SetClass()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var nowDate = DateTime.Now;
|
|||
|
|
string strClass = "";
|
|||
|
|
DateTime time1 = Convert.ToDateTime($"{nowDate.ToShortDateString()} {CommonMethods.ChangeClassTime}");
|
|||
|
|
DateTime time2 = Convert.ToDateTime($"{nowDate.ToShortDateString()} {Convert.ToDateTime(CommonMethods.ChangeClassTime).AddHours(12).ToString("HH:mm:ss")}");
|
|||
|
|
if (nowDate <= time1 && nowDate >= time2)
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.plcDevices[0].IsConnected)
|
|||
|
|
{
|
|||
|
|
if (!qiehuan)
|
|||
|
|
{
|
|||
|
|
if (!SetPlcTime())
|
|||
|
|
{
|
|||
|
|
CommonMethods.AddLog(true, $"PC写入PLC时间失败!".Translated());
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
qiehuan = true;
|
|||
|
|
CommonMethods.AddLog(false, "PC写入PLC时间成功!".Translated());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
strClass = "白班".Translated();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
qiehuan = false;
|
|||
|
|
strClass = "夜班".Translated();
|
|||
|
|
}
|
|||
|
|
CommonMethods.strClass = strClass;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
CommonMethods.AddLog(true, "PC写入PLC时间异常".Translated() + ":" + ex.Message);
|
|||
|
|
LogHelper.Instance.WriteEX(ex);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 写入PLC时间
|
|||
|
|
/// <summary>
|
|||
|
|
/// 写当前时间给PLC
|
|||
|
|
/// </summary>
|
|||
|
|
private bool SetPlcTime()
|
|||
|
|
{
|
|||
|
|
var nowDate = DateTime.Now;
|
|||
|
|
string yearStr = nowDate.Year.ToString();
|
|||
|
|
|
|||
|
|
|
|||
|
|
bool IsSuccess = false;
|
|||
|
|
|
|||
|
|
// 为防止PLC时间出现偏差,每次自动运行的时候写PLC系统时间
|
|||
|
|
short[] writeArr = new short[]
|
|||
|
|
{
|
|||
|
|
Convert.ToInt16(nowDate.Year),//D70
|
|||
|
|
Convert.ToInt16(nowDate.Month),//D71
|
|||
|
|
Convert.ToInt16(nowDate.Day),//D72
|
|||
|
|
Convert.ToInt16(nowDate.Hour),//D73
|
|||
|
|
Convert.ToInt16(nowDate.Minute),//D74
|
|||
|
|
Convert.ToInt16(nowDate.Second),//D75
|
|||
|
|
(short)1 //D76
|
|||
|
|
};
|
|||
|
|
if (CommonMethods.plcDevices[0].IsConnected)
|
|||
|
|
{
|
|||
|
|
JYResult result = CommonMethods.plcDevices[0].WriteValue("D70", writeArr, DataType.ArrShort);
|
|||
|
|
if (result.IsSuccess)
|
|||
|
|
{
|
|||
|
|
IsSuccess = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return IsSuccess;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region 8、IDisposable 实现
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 如果需要在StopAsync中也显示进度,可以添加一个进度回调
|
|||
|
|
|
|||
|
|
private Task processTask;
|
|||
|
|
|
|||
|
|
public async Task StopAsync(IProgress<string> progress = null)
|
|||
|
|
{
|
|||
|
|
_cts.Cancel();
|
|||
|
|
|
|||
|
|
if (_heartbeatTask != null)
|
|||
|
|
{
|
|||
|
|
progress?.Report("正在停止心跳任务...");
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
await _heartbeatTask;
|
|||
|
|
}
|
|||
|
|
catch (OperationCanceledException)
|
|||
|
|
{
|
|||
|
|
// 忽略取消异常
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (processTask != null)
|
|||
|
|
{
|
|||
|
|
progress?.Report("正在停止处理任务...");
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
await processTask;
|
|||
|
|
}
|
|||
|
|
catch (OperationCanceledException)
|
|||
|
|
{
|
|||
|
|
// 忽略取消异常
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
foreach (var pair in groupTasks)
|
|||
|
|
{
|
|||
|
|
progress?.Report($"正在停止组任务: {pair.Key}...");
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
await pair.Value;
|
|||
|
|
}
|
|||
|
|
catch (OperationCanceledException)
|
|||
|
|
{
|
|||
|
|
// 忽略取消异常
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
public void Dispose()
|
|||
|
|
{
|
|||
|
|
Dispose(true);
|
|||
|
|
GC.SuppressFinalize(this);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
protected virtual void Dispose(bool disposing)
|
|||
|
|
{
|
|||
|
|
if (disposing)
|
|||
|
|
{
|
|||
|
|
_cts?.Cancel();
|
|||
|
|
_cts?.Dispose();
|
|||
|
|
|
|||
|
|
processTask?.Wait();
|
|||
|
|
|
|||
|
|
// 断开所有设备连接
|
|||
|
|
foreach (var plc in CommonMethods.plcDevices)
|
|||
|
|
{
|
|||
|
|
plc.Disconnect();
|
|||
|
|
if (plcAlarmReaders.TryGetValue(plc, out var alarmReader))
|
|||
|
|
{
|
|||
|
|
//alarmReader.PLCAlarm_New -= AlrmReader_PLCAlarm_New;
|
|||
|
|
//alarmReader.PLCAlarm_Remove -= AlrmReader_PLCAlarm_Remove;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
CommonMethods.plcDevices.Clear();
|
|||
|
|
plcDeviceMapping.Clear();
|
|||
|
|
plcAlarmReaders.Clear();
|
|||
|
|
CommonMethods.plcStatuses.Clear();
|
|||
|
|
|
|||
|
|
DisconnectAllPlcs();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 7、辅助方法
|
|||
|
|
|
|||
|
|
private static PLCType GetPLCTypeEnum(string plcTypeString)
|
|||
|
|
{
|
|||
|
|
if (Enum.TryParse(plcTypeString, out PLCType plcType))
|
|||
|
|
{
|
|||
|
|
return plcType;
|
|||
|
|
}
|
|||
|
|
throw new ArgumentException($"PLC 类型无效: {plcTypeString}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 8、轴/电机位置监控
|
|||
|
|
private void ReadAxleCSV(int flag, ref List<AxleLog> axleLog, ref List<MotorLog> motorLog)
|
|||
|
|
{
|
|||
|
|
axleLog = new List<AxleLog>();
|
|||
|
|
motorLog = new List<MotorLog>();
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
string strLine = "";
|
|||
|
|
string[] csvReset;//轴位置暂存
|
|||
|
|
string PlcAddress = string.Empty;
|
|||
|
|
bool isExits = false;
|
|||
|
|
switch (flag)
|
|||
|
|
{
|
|||
|
|
case 1://本机轴设定位置
|
|||
|
|
IniConfigHelper.CreateIniFile(configFolderPath, "Motor_ZhiPuJianLouAxle.ini");
|
|||
|
|
if (!File.Exists(Path.Combine(configFolderPath, "Motor_ZhiPuJianLouAxle.ini")))//判断ini文件是否存在
|
|||
|
|
{
|
|||
|
|
isExits = true;
|
|||
|
|
}
|
|||
|
|
using (StreamReader reader = new StreamReader(Path.Combine(configFolderPath, "Motor_ZhiPuJianLouAxle.csv"), System.Text.Encoding.GetEncoding("GB2312")))
|
|||
|
|
{
|
|||
|
|
while ((strLine = reader.ReadLine()) != null)
|
|||
|
|
{
|
|||
|
|
csvReset = strLine.Split(',', '[', ']');
|
|||
|
|
if (csvReset.Length != 5 && csvReset[0] == "")
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (string.IsNullOrEmpty(csvReset[4]) || string.IsNullOrWhiteSpace(csvReset[4]))
|
|||
|
|
{
|
|||
|
|
break; // 空地址跳出读取
|
|||
|
|
}
|
|||
|
|
PlcAddress = csvReset[4];
|
|||
|
|
AxleLog axle = new AxleLog();
|
|||
|
|
axle.m_AxleDscribe = csvReset[0] + csvReset[1];
|
|||
|
|
axle.m_AxleLocation = csvReset[3];
|
|||
|
|
axle.m_AxleAddress = PlcAddress;
|
|||
|
|
axleLog.Add(axle);
|
|||
|
|
if (isExits)
|
|||
|
|
{
|
|||
|
|
string Value = CommonMethods.plcDevices[0].ReadFloat(PlcAddress).ToString();
|
|||
|
|
IniConfigHelper.WriteIniData(axle.m_AxleDscribe, axle.m_AxleLocation, Value, Path.Combine(configFolderPath, "Motor_ZhiPuJianLouAxle.ini"));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
reader.Close();
|
|||
|
|
reader.Dispose();
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 2://本机电机位置设定值motor
|
|||
|
|
IniConfigHelper.CreateIniFile(configFolderPath, "Motor_YiCiWaiGuanMotor.ini");
|
|||
|
|
if (!File.Exists(Path.Combine(configFolderPath, "Motor_YiCiWaiGuanMotor.ini")))//判断ini文件是否存在
|
|||
|
|
{
|
|||
|
|
isExits = true;
|
|||
|
|
}
|
|||
|
|
using (StreamReader reader = new StreamReader(Path.Combine(configFolderPath, "Motor_YiCiWaiGuanMotor.csv"), System.Text.Encoding.GetEncoding("GB2312")))
|
|||
|
|
{
|
|||
|
|
while ((strLine = reader.ReadLine()) != null)
|
|||
|
|
{
|
|||
|
|
csvReset = strLine.Split(',', '[', ']');
|
|||
|
|
if (csvReset.Length != 5 && csvReset[0] == "")
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
if (string.IsNullOrEmpty(csvReset[4]) || string.IsNullOrWhiteSpace(csvReset[4]))
|
|||
|
|
{
|
|||
|
|
break; // 空地址跳出读取
|
|||
|
|
}
|
|||
|
|
PlcAddress = csvReset[4];
|
|||
|
|
MotorLog motor = new MotorLog();
|
|||
|
|
motor.m_MotorDscribe = csvReset[0] + csvReset[1];
|
|||
|
|
motor.m_MotorLocation = csvReset[3];
|
|||
|
|
motor.m_MotorAddress = PlcAddress;
|
|||
|
|
motorLog.Add(motor);
|
|||
|
|
if (isExits)
|
|||
|
|
{
|
|||
|
|
string Value = CommonMethods.plcDevices[0].ReadFloat(PlcAddress).ToString();
|
|||
|
|
IniConfigHelper.WriteIniData(motor.m_MotorDscribe, motor.m_MotorLocation, Value, Path.Combine(configFolderPath, "Motor_YiCiWaiGuanMotor.ini"));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
reader.Close();
|
|||
|
|
reader.Dispose();
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
default: break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
axleLog = null;
|
|||
|
|
motorLog = null;
|
|||
|
|
LogHelper.Instance.WriteError($"轴/电机位置读取配置文件错误:{ex}", "SysErrorLog");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>轴/电机对象集合
|
|||
|
|
///
|
|||
|
|
/// </summary>
|
|||
|
|
private static List<MotorLog> motorLog = new List<MotorLog>();
|
|||
|
|
private static List<AxleLog> axleLog = new List<AxleLog>();
|
|||
|
|
private static Stopwatch swtest = new Stopwatch();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 监控轴位置变化
|
|||
|
|
/// </summary>
|
|||
|
|
public void ShowAxleEven_Run()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)
|
|||
|
|
{
|
|||
|
|
short nowPLCstate = CommonMethods.plcDevices[0].ReadInt16("D10");
|
|||
|
|
if (nowPLCstate != 1)
|
|||
|
|
{
|
|||
|
|
if (axleLog.Count < 1 || motorLog.Count < 1)
|
|||
|
|
{
|
|||
|
|
Thread.Sleep(1500);
|
|||
|
|
ReadAxleCSV(1, ref axleLog, ref motorLog);//轴位置csv文件不存在,out axlelog=null,导致下次判断axlelog.Count报错(未将对象引用设置到对象实例)
|
|||
|
|
Thread.Sleep(1500);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 第二种写法一次读出来
|
|||
|
|
swtest.Restart();
|
|||
|
|
JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"{axleLog[0].m_AxleAddress}", DataType.ArrByte, Convert.ToUInt16(axleLog.Count * 4));
|
|||
|
|
swtest.Stop();
|
|||
|
|
long tempswt = swtest.ElapsedMilliseconds;
|
|||
|
|
|
|||
|
|
swtest.Restart();
|
|||
|
|
if (resByte != null && resByte.IsSuccess && resByte.Content != null)
|
|||
|
|
{
|
|||
|
|
string AxleUpLocationOld;
|
|||
|
|
string AxleUpLocationNew;
|
|||
|
|
for (int i = 0; i < axleLog.Count; i++)
|
|||
|
|
{
|
|||
|
|
double NewCurrent = FloatLib.GetFloatFromByteArray(resByte.Content, i * 4); //D23000 起
|
|||
|
|
AxleUpLocationOld = IniConfigHelper.ReadIniData(axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, "0", Path.Combine(configFolderPath, "Motor_ZhiPuJianLouAxle.ini"));
|
|||
|
|
AxleUpLocationNew = Math.Round(NewCurrent, 2).ToString();
|
|||
|
|
if (AxleUpLocationNew != AxleUpLocationOld)
|
|||
|
|
{
|
|||
|
|
string AlterTime = DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss.fff");
|
|||
|
|
//日期时间,电机描述,位置描述,位置修改前,当前位置
|
|||
|
|
LogHelper.PrintMotorLog.LogInfo(AlterTime, axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, AxleUpLocationOld, AxleUpLocationNew);
|
|||
|
|
IniConfigHelper.WriteIniData(axleLog[i].m_AxleDscribe, axleLog[i].m_AxleLocation, AxleUpLocationNew, Path.Combine(configFolderPath, "Motor_ZhiPuJianLouAxle.ini"));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
swtest.Stop();
|
|||
|
|
tempswt = swtest.ElapsedMilliseconds;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"轴位置监控线程错误:{ex}", "SysErrorLog");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else { Thread.Sleep(5000); }
|
|||
|
|
Thread.Sleep(1000);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"轴位置监控线程错误:{ex}", "SysErrorLog");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 监控电机位置变化
|
|||
|
|
/// </summary>
|
|||
|
|
public void ShowMotorEven_Run()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
if (CommonMethods.plcDevices[0] != null && CommonMethods.plcDevices[0].IsConnected)
|
|||
|
|
{
|
|||
|
|
short nowPLCstate = CommonMethods.plcDevices[0].ReadInt16("D10");
|
|||
|
|
if (nowPLCstate != 1)
|
|||
|
|
{
|
|||
|
|
if (axleLog.Count < 1 || motorLog.Count < 1)
|
|||
|
|
{
|
|||
|
|
Thread.Sleep(3000);
|
|||
|
|
ReadAxleCSV(2, ref axleLog, ref motorLog);//电机位置csv文件不存在,out axlelog=null,导致下次判断axlelog.Count报错(未将对象引用设置到对象实例)
|
|||
|
|
Thread.Sleep(1500);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 第二种写法一次读出来
|
|||
|
|
swtest.Restart();
|
|||
|
|
JYResult<byte[]> resByte = CommonMethods.plcDevices[0].ReadValue<JYResult<byte[]>>($"{motorLog[0].m_MotorAddress}", DataType.ArrByte, Convert.ToUInt16(motorLog.Count * 4));
|
|||
|
|
swtest.Stop();
|
|||
|
|
long tempswt = swtest.ElapsedMilliseconds;
|
|||
|
|
|
|||
|
|
swtest.Restart();
|
|||
|
|
if (resByte != null && resByte.IsSuccess && resByte.Content != null)
|
|||
|
|
{
|
|||
|
|
string MotorUpLocationOld;
|
|||
|
|
string MotorUpLocationNew;
|
|||
|
|
for (int i = 0; i < motorLog.Count; i++)
|
|||
|
|
{
|
|||
|
|
double NewCurrent = FloatLib.GetFloatFromByteArray(resByte.Content, i * 4); //D23000 起
|
|||
|
|
MotorUpLocationOld = IniConfigHelper.ReadIniData(motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, "0", Path.Combine(configFolderPath, "Motor_ZhiPuJianLouAxle.ini"));
|
|||
|
|
MotorUpLocationNew = Math.Round(NewCurrent, 2).ToString();
|
|||
|
|
if (MotorUpLocationNew != MotorUpLocationOld)
|
|||
|
|
{
|
|||
|
|
string AlterTime = DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss.fff");
|
|||
|
|
//日期时间,电机描述,位置描述,位置修改前,当前位置
|
|||
|
|
LogHelper.PrintMotorLog.LogInfo(AlterTime, motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, MotorUpLocationOld, MotorUpLocationNew);
|
|||
|
|
IniConfigHelper.WriteIniData(motorLog[i].m_MotorDscribe, motorLog[i].m_MotorLocation, MotorUpLocationNew, Path.Combine(configFolderPath, "Motor_ZhiPuJianLouAxle.ini"));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
swtest.Stop();
|
|||
|
|
tempswt = swtest.ElapsedMilliseconds;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"电机位置监控线程错误:{ex}", "SysErrorLog");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else { Thread.Sleep(5000); }
|
|||
|
|
Thread.Sleep(1000);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"电机位置监控线程错误:{ex}", "SysErrorLog");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 9、异步删除方法
|
|||
|
|
// 封装删除逻辑
|
|||
|
|
private async Task TryDeleteRfidAsync(string rfid)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 先尝试在 dbServer2 删除
|
|||
|
|
int deletedCount = CommonMethods.dbServer2.Delete<Dataturnover>(it => it.containerCode == rfid);
|
|||
|
|
|
|||
|
|
LogHelper.Instance.WriteLog($"删除RFID: {rfid}, 个数:{deletedCount}", "SysErrorLog");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
LogHelper.Instance.WriteError($"删除RFID异常: {rfid}, {ex}", "SysErrorLog");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
}
|