Files
6150-HMI/CowainHmi/Alarm/AlarmNow.cs
2026-01-15 15:06:36 +08:00

582 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using CowainHmi.UIEditor;
using PCHMI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
namespace CowainHmi.Alarm
{
public partial class AlarmNow : UserControl
{
private string fileName = "";
[Browsable(true)]
[Category("PCHMI"), Description("设置报警文件名称")]
[Editor(typeof(AlarmUIEditor), typeof(UITypeEditor))]
public string FileName
{
get
{
return this.fileName;
}
set
{
this.fileName = value;
}
}
private bool autoShow = true;
[Category("PCHMI"), Description("是否自动弹出报警窗口")]
public bool AutoShow
{
get
{
return autoShow;
}
set
{
autoShow = value;
}
}
private bool linkErrEnable;
[Category("PCHMI"), Description("通讯报警是否捕获")]
public bool LinkErrEnable
{
get
{
return linkErrEnable;
}
set
{
linkErrEnable = value;
}
}
private string upLoadAddr = "";
[Category("PCHMI"), Description("数据上传命令地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string UpLoadAddr
{
get
{
return upLoadAddr;
}
set
{
upLoadAddr = value;
}
}
private string upCountAddr = "";
[Category("PCHMI"), Description("数据上传计数地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string UpCountAddr
{
get
{
return upCountAddr;
}
set
{
upCountAddr = value;
}
}
private string levelAddr = "";
[Category("PCHMI"), Description("报警等级地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string LevelAddr
{
get
{
return levelAddr;
}
set
{
levelAddr = value;
}
}
private string groupAddr = "";
[Category("PCHMI"), Description("报警组地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string GroupAddr
{
get
{
return groupAddr;
}
set
{
groupAddr = value;
}
}
private string idAddr = "";
[Category("PCHMI"), Description("报警ID地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string IdAddr
{
get
{
return idAddr;
}
set
{
idAddr = value;
}
}
private string sd1Addr = "";
[Category("PCHMI"), Description("报警SD1地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string Sd1Addr
{
get
{
return sd1Addr;
}
set
{
sd1Addr = value;
}
}
private string sd2Addr = "";
[Category("PCHMI"), Description("报警SD2地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string Sd2Addr
{
get
{
return sd2Addr;
}
set
{
sd2Addr = value;
}
}
private string sd3Addr = "";
[Category("PCHMI"), Description("报警SD3地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string Sd3Addr
{
get
{
return sd3Addr;
}
set
{
sd3Addr = value;
}
}
private string errTextAddr = "";
[Category("PCHMI"), Description("报警文本地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string ErrTextAddr
{
get
{
return errTextAddr;
}
set
{
errTextAddr = value;
}
}
private string retAddr = "";
[Category("PCHMI"), Description("报警反馈命令地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string RetAddr
{
get
{
return retAddr;
}
set
{
retAddr = value;
}
}
private string retCountAddr = "";
[Category("PCHMI"), Description("报警反馈计数地址")]
[Editor(typeof(StringText), typeof(UITypeEditor))]
public string RetCountAddr
{
get
{
return retCountAddr;
}
set
{
retCountAddr = value;
}
}
private int plcId = 0;
[Category("PCHMI"), Description("PLC编号")]
public int PLCId
{
get
{
return plcId;
}
set
{
plcId = value;
}
}
public int ErrorCount { get; private set; }
public bool Error { get; private set; }
private int retCountSave;
private bool newError;
private bool chgError;
private DataTable _errTable = new DataTable();
private List<AlarmModel> _errList = new List<AlarmModel>();
public AlarmNow()
{
InitializeComponent();
_errTable.Columns.Add("PLC", typeof(string));
_errTable.Columns.Add("DTIM", typeof(string));
_errTable.Columns.Add("报警类别", typeof(string));
_errTable.Columns.Add("报警组", typeof(string));
_errTable.Columns.Add("ID", typeof(string));
_errTable.Columns.Add("ErrText", typeof(string));
_errTable.Columns.Add("TP", typeof(string));
// 确保控件重绘时调用OnPaint
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);
}
private void AlarmNow_Load(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(FileName))
{
FileName = this.Name;
}
InitErrExcel();
//刚打开时加载实时报警表格
var rt = AlarmExcelHelper.GetAlarmRT(FileName);
if (rt != null)
{
var list = rt.Select("TP='1'");
foreach (var item in list)
{
_errTable.Rows.Add(item.ItemArray);
}
}
//初始读一次,相当于注册变量
ushort level = PCHMI.RT.GET_UINT16(PLCId, LevelAddr);
ushort group = PCHMI.RT.GET_UINT16(PLCId, GroupAddr);
int id = PCHMI.RT.GET_UINT16(PLCId, IdAddr) + 10000;
short sd1 = PCHMI.RT.GET_INT16(PLCId, Sd1Addr);
int sd2 = PCHMI.RT.GET_INT32(PLCId, Sd2Addr);
float sd3 = PCHMI.RT.GET_F32(PLCId, Sd3Addr);
string errText = PCHMI.RT.GET_SIEMENS_STRING(PLCId, ErrTextAddr, 100);
ushort count = PCHMI.RT.GET_UINT16(PLCId, UpCountAddr);
short upLoad = PCHMI.RT.GET_INT16(PLCId, UpLoadAddr);
timer1.Enabled = true;
}
private void InitErrExcel()
{
if (!string.IsNullOrEmpty(FileName))
{
//读取报警表格文件
DataTable _errExcel = AlarmExcelHelper.ReadErrExcel(FileName);
if (_errExcel != null && _errExcel.Rows.Count > 0)
{
for (int i = 0; i < _errExcel.Rows.Count; i++)
{
DataRow row = _errExcel.Rows[i];
AlarmModel model = new AlarmModel();
model.PLC = Convert.ToInt32(row["PLC"]);
model.VarType = row["类型"].ToString();
model.Address = row["地址"].ToString();
model.ErrCode = row["代码"].ToString();
model.Level = row["等级"].ToString();
model.Language = new string[] {
row["语言1"].ToString(),
row["语言2"].ToString(),
row["语言3"].ToString(),
row["语言4"].ToString(),
row["语言5"].ToString(),
row["语言6"].ToString(),
row["语言7"].ToString(),
row["语言8"].ToString()
};
if (!int.TryParse(row["触发条件"].ToString(), out int tp))
{
continue;
}
model.TP = tp;
if (!int.TryParse(row["报警组"].ToString(), out int group))
{
continue;
}
model.Group = group;
_errList.Add(model);
}
}
}
}
private bool isFlg = false;
private void timer1_Tick(object sender, EventArgs e)
{
if (isFlg)
{
return;
}
isFlg = true;
if (this.DesignMode)
{
return;
}
if (!PClass.SystemRun)
{
return;
}
//通讯报警
if (LinkErrEnable)
{
for (int i = 0; i < 10; i++)
{
if (!PClass.IsPlcLink(i))
{
//报警发生,查询表格中是否存在此报警
var dr = _errTable.Select($"报警类别='{AlarmType.错误.ToString()}' and 报警组='S' and ID='0'").FirstOrDefault();
if (dr == null)
{
//添加报警到table中
_errTable.Rows.Add(new object[]
{
PLCId.ToString(),
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fffff"),
AlarmType..ToString(),//错误类型
"S",//组
"0",//ID
$"PLC{PLCId},连接异常", //错误信息
"1"
});
newError = true;
}
}
else
{
//通讯报警离开
var dr = _errTable.Select($"报警类别='{AlarmType.错误.ToString()}' and 报警组='S' and ID='0'").FirstOrDefault();
if (dr != null)
{
//删除报警
_errTable.Rows.Remove(dr);
}
}
}
}
if (PClass.IsPlcLink(PLCId) && !string.IsNullOrEmpty(UpLoadAddr))
{
//循环读数据,PLC主动上传报警
ushort level = PCHMI.RT.GET_UINT16(PLCId, LevelAddr);
ushort group = PCHMI.RT.GET_UINT16(PLCId, GroupAddr);
int id = PCHMI.RT.GET_UINT16(PLCId, IdAddr) + 10000;
short sd1 = PCHMI.RT.GET_INT16(PLCId, Sd1Addr);
int sd2 = PCHMI.RT.GET_INT32(PLCId, Sd2Addr);
float sd3 = PCHMI.RT.GET_F32(PLCId, Sd3Addr);
string errText = PCHMI.RT.GET_SIEMENS_STRING(PLCId, ErrTextAddr, 100);
ushort count = PCHMI.RT.GET_UINT16(PLCId, UpCountAddr);
short upLoad = PCHMI.RT.GET_INT16(PLCId, UpLoadAddr);
if (retCountSave != count && upLoad > 0)
{
//计数改变,需要上传数据
string errMsg = errText.Replace("{1}", sd1.ToString()).Replace("{2}", sd2.ToString()).Replace("{3}", sd3.ToString());
string alarmType = ((AlarmType)level).ToString();
if (upLoad == 1)
{
//报警发生,添加报警,还需要写到实时数据库中
var dr = _errTable.Select($"报警类别='{alarmType}' and 报警组='{group}' and ID='{id}'").FirstOrDefault();
if (dr == null)
{
_errTable.Rows.Add(new object[]
{
PLCId.ToString(),
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fffff"),
alarmType,//错误类型
group.ToString(),//组
id.ToString(),//ID
errMsg, //错误信息
"1"
});
AlarmExcelHelper.UpdateAlarmRT(PLCId.ToString(), alarmType, group.ToString(), id.ToString(), errMsg, true, FileName);
AlarmExcelHelper.SaveAlarmLog(PLCId.ToString(), alarmType, group.ToString(), id.ToString(), "1", errMsg);
}
PCHMI.RT.SEND_UINT16(PLCId, RetAddr, 1);
PCHMI.RT.SEND_UINT16(PLCId, RetCountAddr, count);
retCountSave = count;
newError = true;
}
else if (upLoad == 2)
{
//报警离开
var dr = _errTable.Select($"报警类别='{alarmType}' and 报警组='{group}' and ID='{id}'").FirstOrDefault();
if (dr != null)
{
_errTable.Rows.Remove(dr);
AlarmExcelHelper.UpdateAlarmRT(PLCId.ToString(), alarmType, group.ToString(), id.ToString(), errMsg, false, FileName);
AlarmExcelHelper.SaveAlarmLog(PLCId.ToString(), alarmType, group.ToString(), id.ToString(), "0", errMsg);
}
PCHMI.RT.SEND_UINT16(PLCId, RetAddr, 1);
PCHMI.RT.SEND_UINT16(PLCId, RetCountAddr, count);
retCountSave = count;
}
}
}
if (_errList.Count > 0)
{
//判断报警表格中是否有报警发生
foreach (var alarmModel in _errList)
{
if (CONFIG.PLC_OFF[alarmModel.PLC])
{
continue;
}
switch (alarmModel.VarType)
{
case "BIT":
alarmModel.CurValue = (int)PCHMI.RT.GET_BIT(alarmModel.PLC, alarmModel.Address);
break;
case "INT16":
alarmModel.CurValue = (int)PCHMI.RT.GET_INT16(alarmModel.PLC, alarmModel.Address);
break;
case "UINT16":
alarmModel.CurValue = (int)PCHMI.RT.GET_UINT16(alarmModel.PLC, alarmModel.Address);
break;
case "INT32":
alarmModel.CurValue = PCHMI.RT.GET_INT32(alarmModel.PLC, alarmModel.Address);
break;
case "UINT32":
alarmModel.CurValue = (int)PCHMI.RT.GET_UINT32(alarmModel.PLC, alarmModel.Address);
break;
default:
break;
}
if (alarmModel.CurValue != alarmModel.LastValue)
{
//值改变
if (alarmModel.CurValue == alarmModel.TP)
{
//报警发生
var dr = _errTable.Select($"报警类别='{alarmModel.Level}' and 报警组='{alarmModel.Group}' and ID='{alarmModel.ErrCode}'").FirstOrDefault();
if (dr == null)
{
_errTable.Rows.Add(new object[]
{
PLCId.ToString(),
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fffff"),
alarmModel.Level,//错误类型
alarmModel.Group.ToString(),//组
alarmModel.ErrCode.ToString(),//ID
alarmModel.Language[GLOBAL.Language], //错误信息
"1"
});
//AlarmExcelHelper.UpdateAlarmRT(PLCId.ToString(), alarmModel.Level, alarmModel.Group.ToString(), alarmModel.ErrCode.ToString(), alarmModel.Language[GLOBAL.Language], true, FileName);
AlarmExcelHelper.SaveAlarmLog(PLCId.ToString(), alarmModel.Level, alarmModel.Group.ToString(), alarmModel.ErrCode.ToString(), "1", alarmModel.Language[GLOBAL.Language]);
newError = true;
}
}
else
{
//报警离开
var dr = _errTable.Select($"报警类别='{alarmModel.Level}' and 报警组='{alarmModel.Group.ToString()}' and ID='{alarmModel.ErrCode.ToString()}'").FirstOrDefault();
if (dr != null)
{
_errTable.Rows.Remove(dr);
//AlarmExcelHelper.UpdateAlarmRT(PLCId.ToString(), alarmModel.Level, alarmModel.Group.ToString(), alarmModel.ErrCode.ToString(), alarmModel.Language[GLOBAL.Language], false, FileName);
AlarmExcelHelper.SaveAlarmLog(PLCId.ToString(), alarmModel.Level, alarmModel.Group.ToString(), alarmModel.ErrCode.ToString(), "0", alarmModel.Language[GLOBAL.Language]);
}
}
}
alarmModel.LastValue = alarmModel.CurValue;
}
}
ErrorCount = _errTable.Rows.Count;
Error = ErrorCount > 0 ? true : false;
if (Error)
{
//有报警
chgError = !chgError;
//控制报警图标闪烁
this.BackgroundImage = chgError ? global::CowainHmi.Properties.Resources.alarm1 : global::CowainHmi.Properties.Resources.Alarm;
if (newError & this.AutoShow)
{
//有新报警出现,自动弹窗
ShowErrDlg();
}
}
else
{
//无报警
this.BackgroundImage = global::CowainHmi.Properties.Resources.alarm1;
}
isFlg = false;
}
DlgAlarmNow dlgAlarm;
private void ShowErrDlg()
{
//弹出报警窗口
if (dlgAlarm == null)
{
dlgAlarm = new DlgAlarmNow(_errTable);
}
dlgAlarm.Show(); //显示窗体
dlgAlarm.WindowState = FormWindowState.Normal;
dlgAlarm.Activate();
newError = false;
}
private void AlarmNow_MouseDown(object sender, MouseEventArgs e)
{
ShowErrDlg();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (ErrorCount == 0)
{
return;
}
using (Brush brush = new SolidBrush(ForeColor))
{
// 获取Graphics对象
Graphics g = e.Graphics;
// 获取控件的绘制区域
// 计算字符串绘制的起始位置(控件的右上角,留出一些内边距)
//PointF textPosition = new PointF(this.Width - g.MeasureString(ErrorCount.ToString(), this.Font).Width - padding, padding);
PointF textPosition = new PointF(1, 7);
// 设置字符串格式这里我们使用StringFormat来居中字符串
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Near;
sf.LineAlignment = StringAlignment.Center;
g.DrawString(ErrorCount.ToString(), this.Font, brush, textPosition, sf);
sf.Dispose();
}
}
}
}