开发者中心 开发者中心
  • 简体中文
  • English
视频教程
敢为云网站
  • 6.0版本
  • 6.1 版本
视频教程
敢为云网站
  • 平台概述
  • 平台功能
  • 平台安装
  • 开发者指南
    • 协议插件开发
      • 入门
      • 进阶
      • GWDataCenter常用接口API
    • 扩展插件开发
    • 报警插件开发
      • 概述
      • 开发框架
    • 应用插件开发
    • Web可视化开发
    • 3D可视化开发
    • 桌面可视化开发
    • 小程序开发
  • 项目实战
  • 附录

报警插件开发

# 开发指南

介绍报警插件的开发

# 概述

概述

报警插件是IoTCenter提供的对外报警方式,是由测点触发,比如短信报警、邮件报警、声光报警等。报警插件配置方式如下:

字段含义:

字段 说明
Proc_Code 模块编码,按位编码,前两位已经被系统占用(1和2),编码只能是4、8、16...
Proc_Module 报警模块dll的名称
Proc_name 报警方式
Proc_parm 参数配置:自行定义,在报警dll中解析
Comment 备注说明

配置好报警模块后,系统配置界面中会自动出现相关的报警方式供选择:

img

# 开发框架

接下来以Email报警模块的代码为例,讲解开发过程:
using GWDataCenter;
using GWDataCenter.Database;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Threading;

namespace AlarmCenter.AlarmHandle.GWEmailPro
{
    public class CAlarm : CAlarmEquipBase
    {
        const int ThreadInterval = 10*1000;//间隔10秒
        const int RetryTimes = 3;//报警失败重复次数
        Thread AlarmScanThread;
        SendEmail MyEmail = null;
        string strParm;
        string ModuleNm;
        string MailAddress, PassWord, Title, SendNm, ReceiveNm, MailServer, SMPTPort,LocalPort;
        CAlarmItem CurrentAlarmItem = null;

        public void StartAlarmThread()
        {
            ThreadStart entryPoint = new ThreadStart(AlarmScan);
            AlarmScanThread = new Thread(entryPoint);
            AlarmScanThread.IsBackground = true;
            AlarmScanThread.Start();
        }

        public void AlarmScan()
        {
            while (true)
            {
                if (CurrentAlarmItem != null)
                {
                    DoAlarm(CurrentAlarmItem);
                    CurrentAlarmItem = null;
                }

                lock (AlarmItemQueue)
                {
                    if (AlarmItemQueue.Count > 0)
                    {
                        CurrentAlarmItem = (CAlarmItem)AlarmItemQueue.Dequeue();
                    }
                }
                ThreadPool.QueueUserWorkItem(new WaitCallback(CheckRise));
                Thread.Sleep(500);
            }
        }

        //每隔一秒钟检查延时报警列表
        void CheckRise(object o)
        {
            Thread.Sleep(1000);
            CheckAlarmRise();
        }

        public override bool init(AlarmProcTableRow Row)
        {
            try
            {
                if (MyEmail == null)
                    MyEmail = new SendEmail();
                strParm = Row.Proc_parm;
                ModuleNm = Row.Proc_name;
                if (strParm.IndexOf(';') > 0)
                {
                    MailAddress = strParm.Split(';')[0];
                    if (MailAddress.IndexOf('=') > 0)
                    {
                        MailAddress = MailAddress.Split('=')[1].Trim();
                    }

                    PassWord = strParm.Split(';')[1];
                    if (PassWord.IndexOf('=') > 0)
                    {
                        PassWord = PassWord.Split('=')[1].Trim();
                    }

                    Title = strParm.Split(';')[2];
                    if (Title.IndexOf('=') > 0)
                    {
                        Title = Title.Split('=')[1].Trim();
                    }

                    SendNm = strParm.Split(';')[3];
                    if (SendNm.IndexOf('=') > 0)
                    {
                        SendNm = SendNm.Split('=')[1].Trim();
                    }

                    ReceiveNm = strParm.Split(';')[4];
                    if (ReceiveNm.IndexOf('=') > 0)
                    {
                        ReceiveNm = ReceiveNm.Split('=')[1].Trim();
                    }

                    MailServer = strParm.Split(';')[5];
                    if (MailServer.IndexOf('=') > 0)
                    {
                        MailServer = MailServer.Split('=')[1].Trim();
                    }

                    SMPTPort = strParm.Split(';')[6];
                    if (SMPTPort.IndexOf('=') > 0)
                    {
                        SMPTPort = SMPTPort.Split('=')[1].Trim();
                    }

                    LocalPort = strParm.Split(';')[7];
                    if (LocalPort.IndexOf('=') > 0)
                    {
                        LocalPort = LocalPort.Split('=')[1].Trim();
                    }

                    StartAlarmThread();
                }
            }
            catch (Exception e)
            {
                MessageService.AddMessage(MessageLevel.Fatal, General.GetExceptionInfo(e), 0, false);
            }
            return true;
        }

        public override bool DoAlarm(CAlarmItem item)
        {
            List<AdministratorTableRow> dt = item.GetAdminsOfAlarm(item.Equipno, item.Time);//得到报警人员列表
            foreach (AdministratorTableRow r in dt)
            {
                try
                {
                    int level;
                    level = r.AckLevel.GetType() == typeof(System.DBNull) ? 0 : r.AckLevel;
                    if (level == item.AlarmLevel)//同一级别才报警
                    {
                        string Content = item.Time.ToString("HH:mm:ss ") + item.Event;
                        int iPort = Convert.ToInt32(SMPTPort);
                        int iLocalPort = Convert.ToInt32(LocalPort);
                        //数据库里面的Email地址已经加密,需要解密
                        string strEmail = GWDataCenter.DataCenter.MD5Decrypt(r.EMail, GWDataCenter.DataCenter.GeneratMD5Key());
                        if (!MyEmail.Init(MailAddress, PassWord, strEmail, Title, ReceiveNm, SendNm, MailServer, iPort, iLocalPort))
                        {
                            string msg1 = string.Format("{0}:{1}--{2}--{3}", strEmail,
                            ResourceService.GetString("AlarmCenter.Email.Msg1", "发送Email报警"),
                            item.Event,
                            ResourceService.GetString("AlarmCenter.Email.Msg3", "失败!"));
                            MessageService.AddMessage(MessageLevel.Info, msg1, 0, false);

                            lock (GWDbProvider.lockstate)
                            {
                                using (var db = StationItem.MyGWDbProvider.serviceProvider.GetService<GWDataContext>())
                                {
                                    var Row = new AlarmRecTableRow
                                    {
                                        proc_name = ModuleNm,
                                        Administrator = r.Administrator,
                                        gwEvent = item.Event,
                                        time = General.Convert2DT(DateTime.Now),
                                        comment = ResourceService.GetString("AlarmCenter.Email.Msg3")
                                    };
                                    db.AlarmRecTable.Add(Row);
                                    db.SaveChanges();
                                 }
                            }
                            continue;
                        }
                        MyEmail.SendBodyTxt(Content);//设置发邮件内容
                        MyEmail.Send();
                        string msg = string.Format("{0}:{1}--{2}--{3}", strEmail,
                        ResourceService.GetString("AlarmCenter.Email.Msg1", "发送Email报警"),
                        item.Event,
                        ResourceService.GetString("AlarmCenter.Email.Msg2", "成功!"));
                        MessageService.AddMessage(MessageLevel.Info, msg, 0);

                        lock (GWDbProvider.lockstate)
                        {
                            using (var db = StationItem.MyGWDbProvider.serviceProvider.GetService<GWDataContext>())
                            {
                                var Row = new AlarmRecTableRow
                                {
                                    proc_name = ModuleNm,
                                    Administrator = r.Administrator,
                                    gwEvent = item.Event,
                                    time = General.Convert2DT(DateTime.Now),
                                    comment = "报警成功"
                                };
                                db.AlarmRecTable.Add(Row);
                                db.SaveChanges();
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    GWDataCenter.DataCenter.WriteLogFile(General.GetExceptionInfo(e));
                    Thread.Sleep(5000);
                    MyEmail = null;
                    MyEmail = new SendEmail();
                    //MessageService.AddMessage(MessageLevel.Warn, General.GetExceptionInfo(e), 0, false);
                }
            }

            return true;
        }
    }
}

public class CAlarm : CAlarmEquipBase报警模块的类名必须是CAlarm,从 CAlarmEquipBase 类派生。CAlarmEquipBase类包含在GWDataCenter包中,GWDataCenter是IoTCenter的核心库。看看Email报警模块的依赖包:

img

IoTCenter启动时,会加载配置好的报警插件,自动调用public override bool init(AlarmProcTableRow Row)。AlarmProcTableRow Row就是配置行的实体对象。init函数主要作用是解析数据库中配置的参数,同时启动一个报警扫描线程:StartAlarmThread()。

重点讲解一下报警扫描函数:

报警扫描函数代码
public void AlarmScan()
{
    while (true)
    {
        if (CurrentAlarmItem != null)
        {
            DoAlarm(CurrentAlarmItem);
            CurrentAlarmItem = null;
        }

        lock (AlarmItemQueue)
        {
            if (AlarmItemQueue.Count > 0)
            {
                CurrentAlarmItem = (CAlarmItem)AlarmItemQueue.Dequeue();
            }
        }
        ThreadPool.QueueUserWorkItem(new WaitCallback(CheckRise));
        Thread.Sleep(500);
    }
}

AlarmItemQueue是CAlarmEquipBase中的报警项CAlarmItem队列,队列如果存在报警项,就会调用处理函数DoAlarm(CurrentAlarmItem)。同时AlarmScan还会调用CheckRise,用于检查报警升级周期。

我们看看CAlarmItem的字段定义:

CAlarmItem的字段定义
public class CAlarmItem
{
    public int Equipno;//报警设备号
    public string Type;//报警类型:EQUIP报警为"E",YCP报警为"C",YXP报警为"X"
    public int YcYxNo;//测点号
    public string Event;//报警事件描述
    public string Wave;//报警对应的声音文件
    public DateTime Time;//报警发生的时间
    public int Retrys;//重试次数
    public bool IsAlarm;//报警状态:true--报警;false--不报警
    public bool IsSendAlarm;//是否发送报警
    public int? AlarmRiseCycle;//报警升级周期:分钟
    public int AlarmLevel=0;//报警通知级别:报警排班中不同人员对应不同级别,这个级别与报警升级周期关联,定时升级
}

CheckRise 就是根据 CAlarmItem 中的 AlarmRiseCycle,获取当前 CAlarmItem 中的 AlarmLevel。

在人员的报警排班中,有对应的报警级别设置:

img

报警通知级别的作用是用于分级报警,比如测点A发生报警,如果AlarmRiseCycle设为15,即报警升级周期是15分钟。当A发生报警后,如果在15分钟内没有恢复正常,报警通知级别升为1;如果30分钟内还没有得到处理,则报警通知级别升为2。这样,我们可以把某个维护人员的通知级别设为0,把他的上级领导设为1,把他领导的领导设为2,这样就实现了报警的分级通知管理。

img

public override bool DoAlarm(CAlarmItem item)是处理当前报警的函数,说明如下:

List<AdministratorTableRow> dt = item.GetAdminsOfAlarm(item.Equipno, item.Time);得到有权限接收当前报警的人员列表

只有同一通知级别才报警:

level = r.AckLevel.GetType() == typeof(System.DBNull) ? 0 : r.AckLevel;
if (level == item.AlarmLevel)//同一级别才报警
{
    //发送报警...
}  

以下代码块是保存报警处理事件到数据库AlarmRec表的标准操作:

代码
lock (GWDbProvider.lockstate)
{
    using (var db = StationItem.MyGWDbProvider.serviceProvider.GetService<GWDataContext>())
    {
        var Row = new AlarmRecTableRow
        {
            proc_name = ModuleNm,
            Administrator = r.Administrator,
            gwEvent = item.Event,
            time = General.Convert2DT(DateTime.Now),
            comment = ResourceService.GetString("报警成功")
        };
        db.AlarmRecTable.Add(Row);
        db.SaveChanges();
    }
    continue;
}

注意

获取报警方式

显示报警:var result = (alarm_scheme & 1) == 1 ? 1 : 0;

记录报警:var result = (alarm_scheme & 2) == 2 ? 1 : 0;

短信报警:var result = (alarm_scheme & 4) == 4 ? 1 : 0;

Email报警:var result = (alarm_scheme & 8) == 8 ? 1 : 0;

工单报警:var result = (alarm_scheme & 16) == 16 ? 1 :0;

当result 为1时说明支持当前属性。

注:Equip(设备表)、YCP(遥测表)、YXP(遥信表)均存在alarm_scheme字段。

具体怎么实现的邮件报警不再阐述,开发者熟悉框架结构就可以开发出各种报警模块了。

上次更新: 12/12/2023, 7:27:04 PM

← 进阶 基于脚手架开发→

目录
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式