src/Bro.M141.Process/M141Process.cs
@@ -5,10 +5,12 @@
using Bro.Device.InsCamera;
using Bro.M135.Common;
using Bro.M135.DBManager;
using Bro.M141.Process.UI;
using Bro.Process;
using Bro.Process.DataBase.Models;
using Bro.UI.Model.Winform;
using HalconDotNet;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;
@@ -56,6 +58,8 @@
        public M141Process_Mysql mysqlhelper = new M141Process_Mysql();
        public event Action RerefreshBasketcodeUI;
        public Action<bool, string> OnContinuousNGAlarmRaised;
        public void RerefreshBasketcode()
        {
@@ -133,10 +137,10 @@
                mqtt.Connect(M141Config.MESchannel);
            }
            InitialContinuousNGAlarm();
        }
        public override void Close()
        {
            devicestate = false;
@@ -571,11 +575,8 @@
                                double y1 = item1.Rect.Point_LU.Y + item1.Rect.Height / 2.0;
                                num++;
                                //HOperatorSet.AffineTransPoint2d(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
                                //HOperatorSet.ProjectiveTransPixel(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"{products[0].SN}  S3S5检测  原坐标{num}   {x1},{y1}");
                                HOperatorSet.ProjectiveTransPixel(new HTuple(products[0].Centermatrix.ToArray()), x1, y1, out HTuple qx, out HTuple qy);
                                HOperatorSet.ProjectiveTransPixel(new HTuple(products[0].Centermatrix.ToArray()), y1, x1, out HTuple qx, out HTuple qy);
                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Detail, $"{products[0].SN}  S3S5检测  新坐标{num}   {qx},{qy}");
@@ -589,6 +590,7 @@
                                {
                                    item1.IsAbandoned = false;
                                    item1.FinalResult = ResultState.NG;
                                    //products[0].Result = M141Config.defectname;
                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"产品{products[0].PID}_{products[0].SEQUENCE}工位{measureBind.WorkPosition}   S3S5组合检测检出缺陷:{item1.NetName},产品结果为{products[0].Result}");
                                    break;
@@ -741,7 +743,7 @@
                                        post = M141Config.ImageFormatOK.ToString().ToLower();
                                    }
                                    string ngImageFile = Path.Combine(folder, $"{id}.{post}");
                                    string ngImageFile = Path.Combine(folder, $"{id}.{post}");
                                    //var bitmap = imgSet.HImage.ConvertHImageToBitmap();
                                    //bitmap.Save(ngImageFile, M141Config.ImageFormatOK);
                                    //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}OK图片已保存");
@@ -749,7 +751,7 @@
                                    try
                                    {
                                        LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{id}OK图片测试转存{ngImageFile}");
                                        imgSet.HImage.WriteImage(M141Config.ImageFormatOK.ToString().ToLower(), 0, ngImageFile);
                                        imgSet.HImage.WriteImage(M141Config.ImageFormatOK.ToString().ToLower(), 0, ngImageFile);
                                    }
                                    catch (Exception)
                                    {
@@ -1239,13 +1241,66 @@
                        mysqlhelper.UpdateProduct(p);
                        if (positionSet.IsLastPosition)
                        {
                            UpdateProductResultAsync(p);
                            //班次统计时间划分
                            if (M141Config.WorkShiftList.Count == 0)
                            {
                                //生成一个报表
                                string name = $"ProductRecord_{DateTime.Now.ToString("yyyyMMdd")}.csv";
                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"创建{name}数据报表");
                                UpdateProductResultAsync(p, name);
                            }
                            else
                            {
                                foreach (var item in M141Config.WorkShiftList)
                                {
                                    DateTime now = DateTime.Now;
                                    if (item.ShiftTime_Start < item.ShiftTime_End)
                                    {
                                        if (now.TimeOfDay >= item.ShiftTime_Start.TimeOfDay && now.TimeOfDay < item.ShiftTime_End.TimeOfDay)
                                        {
                                            //生成一个报表
                                            string name = $"ProductRecord_{DateTime.Now.ToString("yyyyMMdd")}_{item.ShiftName}.csv";
                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"创建{name}数据报表");
                                            UpdateProductResultAsync(p, name);
                                        }
                                    }
                                    else
                                    {
                                        if (now.TimeOfDay >= item.ShiftTime_Start.TimeOfDay )
                                        {
                                            //生成一个报表
                                            string name = $"ProductRecord_{DateTime.Now.ToString("yyyyMMdd")}_{item.ShiftName}.csv";
                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"创建{name}数据报表");
                                            UpdateProductResultAsync(p, name);
                                        }
                                        if (now.TimeOfDay < item.ShiftTime_End.TimeOfDay)
                                        {
                                            // 生成一个报表
                                            string name = $"ProductRecord_{DateTime.Now.AddDays(-1).ToString("yyyyMMdd")}_{item.ShiftName}.csv";
                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"创建{name}数据报表");
                                            UpdateProductResultAsync(p, name);
                                        }
                                    }
                                }
                            }
                            //UpdateProductResultAsync(p);
                            mysqlhelper.NewForAll(p, M141Config.StationCode, M141Config.defectname);
                            if (M141Config.IsfinDevice)
                            {
                                SummaryAllprodata(p);
                            }
                        }
                    });
@@ -1281,7 +1336,7 @@
                            if (pList[0].Result == "OK")
                            {
                                M141Config.numpro++;
                                M141Config.numpro++;
                                Msgreceice = Task.Run(() => mqtt.MESForProduceAsync(pList[0], M141Config.mesnum2.ToString(), M141Config.numpro)).Result;
                            }
                            else
@@ -1290,16 +1345,24 @@
                                {
                                    Msgreceice = Task.Run(() => mqtt.MESForProduceAsync(pList[0], M141Config.mesnum2.ToString(), M141Config.numpro)).Result;
                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{pList[0].PID}启动NG上传");
                                }
                                else
                                {
                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{pList[0].PID}关闭NG上传");
                                }
                            }
                                }
                            }
                            M141Config.mesnum2++;
                            if (Msgreceice == null)
                            if (Msgreceice == null && !M141Config.ISupNG)
                            {
                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{pList[0].PID}数据上传MES异常 返回数据为null");
                                if (!M141Config.ISupNG)
                                {
                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{pList[0].PID}数据NG,开启关闭NG上传MES");
                                }
                                else
                                {
                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{pList[0].PID}数据上传MES异常 返回数据为null");
                                }
                            }
                            else
                            {
@@ -1363,11 +1426,11 @@
                                            {
                                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{newp.PID}关闭NG上传");
                                            }
                                        }
                                        catch
                                        {
                                            LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{i + "_1"}上传失败");
                                        }
                                    }
                                }
@@ -1375,7 +1438,7 @@
                                {
                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"生产过程中未失去产品");
                                }
                                else if ( differ<0 && differ>-29998)
                                else if (differ < 0 && differ > -29998)
                                {
                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"PlcNumForAll为{PlcNumForAll},numplca为{numplca}");
                                    //产品从新计数时
@@ -1404,7 +1467,7 @@
                                            //var tems = Task.Run(() => mqtt.MESForProduceAsync(newp, M141Config.mesnum2.ToString(), M141Config.numpro)).Result;
                                            //M141Config.mesnum2++;
                                            //LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"PlcNumForAll,前站NG排料且plc触发清零产品{newp.PID}数据上传,结果为{newp.Result}");
                                        }
                                        catch
                                        {
@@ -1452,8 +1515,6 @@
                    //ReplyPlcData(positionName, config.TriggerValue);
                    return pList;
                }
@@ -1480,6 +1541,7 @@
        public void SummaryAllprodata(ProductModel p)
        {
            _taskFactory.StartNew(() =>
            {
                try
@@ -1503,6 +1565,7 @@
                            newp.Details.AddRange(item.Details);
                        }
                    }
                    //LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"AllDeviceProductRecord从数据库获取到数据{p.SEQUENCE} plist数量{plist.Count} Details数量{newp.Details.Count}");
                    //newp.Details.AddRange(p.Details);
@@ -1525,10 +1588,284 @@
        #endregion
        List<DefectNGRecord> DefectNGRecordList = new List<DefectNGRecord>();
        public void InitialContinuousNGAlarm()
        {
            DefectNGRecordList = M141Config.ContinuousNGAlarmColletion.Where(u => u.IsEnabled).Select(u =>
            {
                DefectNGRecord record = new DefectNGRecord();
                record.DefectName = u.DefectType;
                record.AlarmSetting = u;
                return record;
            }).ToList();
            OnContinuousNGAlarmRaised = NGAlarmRaised;
            if (M141Config.ContinuousNGAlarmAddress > 0 && Plc1 != null)
            {
                if (!Plc1.WriteSingleAddress(M141Config.ContinuousNGAlarmAddress, 0, out string error))
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"连续NG监控通知PLC重置报警失败,{error}");
                }
            }
        }
        public async void CheckContinuousNGAlarmAsync(ProductModel product)
        {
            await Task.Run(() =>
            {
                if (!M141Config.IsEnableContinuousNGAlarm)
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"连续NG报警总开关已关闭");
                    return;
                }
                if (DefectNGRecordList.Count == 0)
                    return;
                string allMsg = "";
                bool isAlarmRaised = false;
                int alarmType = 0;
                string ngItem = "";
                try
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"连续NG数据记录");
                    DefectNGRecordList.ForEach(d =>
                    {
                            string alarmMsg = "";
                            int alarmTypeTemp = 0;
                            if (product.Result == "OK")
                            {
                                if (d.CheckIsAlarmRaised(product.Result == "OK", out alarmMsg, out alarmTypeTemp))
                                {
                                    allMsg += $"{alarmMsg}\r\n";
                                    isAlarmRaised = true;
                                    ngItem = "产品结果";
                                    alarmType = alarmTypeTemp;
                                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{product.PID}数据结果为{product.Result}参与连续NG统计");
                                }
                            }
                            else
                            {
                                if (product.Result.Contains(d.DefectName))
                                {
                                    if (d.CheckIsAlarmRaised(!product.Result.Contains(d.DefectName), out alarmMsg, out alarmTypeTemp))
                                    {
                                        allMsg += $"{alarmMsg}\r\n";
                                        isAlarmRaised = true;
                                        ngItem = "产品结果";
                                        alarmType = alarmTypeTemp;
                                        LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{product.PID}数据结果为{product.Result}参与连续NG统计");
                                    }
                                }
                            }
                    });
                }
                catch (Exception ex)
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"连续NG数据记录失败");
                }
                if (isAlarmRaised)
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Warning, $"连续NG监控报警,{allMsg}");
                    if (M141Config.IsOperatorReset)
                    {
                        if (M141Config.ContinuousNGAlarmAddress > 0 && Plc1 != null)
                        {
                            if (!Plc1.WriteSingleAddress(M141Config.ContinuousNGAlarmAddress, 1, out string error))
                            {
                                LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"连续NG监控通知PLC重置报警失败,{error}");
                            }
                        }
                        OnContinuousNGAlarmRaised?.Invoke(true, allMsg);
                    }
                    else
                    {
                        Task.Delay(50).Wait();
                        ResetContinuousNGAlarm();
                    }
                }
            });
        }
        object _continuousNGAlarmLock = new object();
        FrmContinuousNGAlarm _continuousNGAlarmFrm = null;
        private async void NGAlarmRaised(bool isRaiseAlarm, string alarmMsg)
        {
            await Task.Run(() =>
            {
                if (isRaiseAlarm)
                {
                    if (_continuousNGAlarmFrm == null)
                    {
                        lock (_continuousNGAlarmLock)
                        {
                            if (_continuousNGAlarmFrm == null)
                            {
                                _continuousNGAlarmFrm = new FrmContinuousNGAlarm();
                                _continuousNGAlarmFrm.TopMost = true;
                                _continuousNGAlarmFrm.FormClosed += _continuousNGAlarmFrm_FormClosed;
                                Task.Run(() =>
                                {
                                    _continuousNGAlarmFrm.ShowDialog();
                                });
                            }
                        }
                    }
                    Task.Delay(100).Wait();
                    _continuousNGAlarmFrm.ShowAlarmMsg(alarmMsg);
                }
                else
                {
                    if (_continuousNGAlarmFrm != null)
                    {
                        _continuousNGAlarmFrm.Close();
                    }
                }
            });
        }
        private void _continuousNGAlarmFrm_FormClosed(object? sender, FormClosedEventArgs e)
        {
            ResetContinuousNGAlarm();
            LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"连续NG报警已复位");
            _continuousNGAlarmFrm = null;
        }
        public void ResetContinuousNGAlarm()
        {
            //连续NG复位
            DefectNGRecordList.Where(u => u.IsAlarmRaised).ToList().ForEach(u => u.ResetAlarm());
            if (M141Config.ContinuousNGAlarmAddress > 0 && Plc1 != null)
            {
                if (!Plc1.WriteSingleAddress(M141Config.ContinuousNGAlarmAddress, 0, out string error))
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"连续NG监控通知PLC重置报警失败,{error}");
                }
            }
        }
        [ProcessMethod("", "ContinuousNGAlarmTest", "连续NG报警测试", InvokeType.TestInvoke)]
        public ResponseMessage ContinuousNGAlarmTest(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
        {
            ProductModel p = new ProductModel();
            p.Result = config.TriggerStr;
            CheckContinuousNGAlarmAsync(p);
            return new ResponseMessage();
        }
    }
    public class DefectNGRecord
    {
        public string DefectName { get; set; }
        public List<DateTime> NGRecords { get; set; } = new List<DateTime>();
        public int ContinuousNGNum { get; set; } = 0;
        public ContinuousNGAlarm AlarmSetting { get; set; }
        private object _lockObj = new object();
        public bool IsAlarmRaised = false;
        bool _isContinuousAlarm = false;
}
        bool _timeAlarm = false;
        public bool CheckIsAlarmRaised(bool isOK, out string alarmMsg, out int alarmType)
        {
            alarmType = 0;
            alarmMsg = "";
            bool isAlarmRasied = false;
            if (IsAlarmRaised)
                return false;
            lock (_lockObj)
            {
                if (IsAlarmRaised)
                    return false;
                if (isOK)
                {
                    ContinuousNGNum = 0;
                }
                else
                {
                    //连续NG数量阈值
                    if (AlarmSetting.ContinuousNumThreshold > 0)
                    {
                        ContinuousNGNum++;
                        CommonLogger.LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{DefectName}连续NG数量为:{ContinuousNGNum}个");
                    }
                    //时间内NG数量阈值
                    if (AlarmSetting.TimePeriodNumThresold > 0)
                    {
                        NGRecords.Add(DateTime.Now);
                    }
                }
                if (NGRecords.Count >= AlarmSetting.TimePeriodNumThresold && NGRecords.Count > 0)
                {
                    NGRecords = NGRecords.Skip(NGRecords.Count - AlarmSetting.TimePeriodNumThresold).OrderBy(u => u).ToList();
                    int timeInMinute = (int)Math.Ceiling((NGRecords[NGRecords.Count - 1] - NGRecords[0]).TotalMinutes);
                    //监控时间段
                    if (timeInMinute <= AlarmSetting.TimePeriod)
                    {
                        isAlarmRasied = true;
                        alarmMsg += $"{DefectName}{timeInMinute}分钟内NG{NGRecords.Count}个 ";
                        alarmType = AlarmSetting.TimePeriodAlarmType;
                        _timeAlarm = true;
                    }
                }
                if (ContinuousNGNum >= AlarmSetting.ContinuousNumThreshold)
                {
                    isAlarmRasied = true;
                    alarmMsg += $"{DefectName}连续NG{ContinuousNGNum}个 ";
                    alarmType = AlarmSetting.ContinuousAlarmType;
                    _isContinuousAlarm = true;
                }
                IsAlarmRaised = isAlarmRasied;
                return isAlarmRasied;
            }
        }
        public void ResetAlarm()
        {
            string msg = "";
            lock (_lockObj)
            {
                IsAlarmRaised = false;
                if (_isContinuousAlarm)
                {
                    _isContinuousAlarm = false;
                    ContinuousNGNum = 0;
                    msg += "连续NG报警 ";
                }
                if (_timeAlarm)
                {
                    _timeAlarm = false;
                    NGRecords.Clear();
                    msg += "时段内NG报警 ";
                }
            }
            CommonLogger.LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"{DefectName}{msg}已重置");
        }
    }
}